我正在使用Groovy构建一个分析应用程序,并需要非常宽容的数学运算符,无论数据格式如何。我通过运算符重载来实现这一点,在许多情况下改善了(在我的情况下)默认的Groovy类型灵活性。例如,我需要123.45f +“05”等于128.45f。默认情况下,Groovy会降级为字符串,结果我得到123.4505。
在大多数情况下,我的重载工作得非常好,但对于比较运算符却不行。我已经跟随了几个讨论,但是没有得到答案,我正在寻找想法。我认识到目标是重载compareTo(与lessThan之类的东西不同),但是Groovy似乎忽略了这一点,而是尝试自己智能比较-例如DefaultTypeTransformation.compareTo(Object left,Object right),但在混合类型上失败。
不幸的是,这对我来说是必须的,因为错误地比较两个值会损害整个解决方案,而我无法控制正在分析的某些数据类型(例如供应商数据结构)。
例如,我需要以下内容正常工作:
当我尝试上述测试时,没有任何一个被调用,反而出现了:
在大多数情况下,我的重载工作得非常好,但对于比较运算符却不行。我已经跟随了几个讨论,但是没有得到答案,我正在寻找想法。我认识到目标是重载compareTo(与lessThan之类的东西不同),但是Groovy似乎忽略了这一点,而是尝试自己智能比较-例如DefaultTypeTransformation.compareTo(Object left,Object right),但在混合类型上失败。
不幸的是,这对我来说是必须的,因为错误地比较两个值会损害整个解决方案,而我无法控制正在分析的某些数据类型(例如供应商数据结构)。
例如,我需要以下内容正常工作:
Float f = 123.45f;
String s = "0300";
Assert.assertTrue( f < s );
我有许多这样的排列组合,但是我的尝试重载包括(假设如果我能让Groovy调用它,我的JavaTypeUtil会完成我需要的工作):
// overloads on startup, trying to catch all cases
Float.metaClass.compareTo = {
Object o -> JavaTypeUtil.compareTo(delegate, o) }
Float.metaClass.compareTo = {
String s -> JavaTypeUtil.compareTo(delegate, s) }
Object.metaClass.compareTo = {
String s -> JavaTypeUtil.compareTo(delegate, s) }
Object.metaClass.compareTo = {
Object o -> JavaTypeUtil.compareTo(delegate, o) }
当我尝试上述测试时,没有任何一个被调用,反而出现了:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Float
at java.lang.Float.compareTo(Float.java:50)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareToWithEqualityCheck(DefaultTypeTransformation.java:585)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareTo(DefaultTypeTransformation.java:540)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareTo(ScriptBytecodeAdapter.java:690)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareLessThan(ScriptBytecodeAdapter.java:710)
at com.modelshop.datacore.generator.GroovyMathTests.testMath(GroovyMathTests.groovy:32)
通过调试,我发现 < 运算符直接进入 ScriptBytecodeAdapter.compareLessThan(),而该函数的实现似乎忽略了此处重载的 compareTo() 函数:
在 DefaultTypeTransformations.java 的第 584 行(2.4.3 版本)中:
if (!equalityCheckOnly || left.getClass().isAssignableFrom(right.getClass())
|| (right.getClass() != Object.class && right.getClass().isAssignableFrom(left.getClass())) //GROOVY-4046
|| (left instanceof GString && right instanceof String)) {
Comparable comparable = (Comparable) left;
return comparable.compareTo(right); // <--- ***
}
在绝望的情况下,我也试图重载compareLessThan方法,但是现在我感到困惑,我不知道是否有任何方式可以在Groovy中跳过<映射。
Float.metaClass.compareLessThan << {
Object right -> JavaTypeUtil.compareTo(delegate, right) < 0 }
Float.metaClass.compareLessThan << {
String right -> JavaTypeUtil.compareTo(delegate, right) < 0 }
有没有关于解决方法的想法?谢谢!
Float.metaClass.static.compareTo = { String s -> 0 }; Float f = 7.0f; String s ='str'; assert f.compareTo(s)== 0
,这更接近,但仍然不是你想要的。 - Keegan