Groovy compareTo for CustomClass和数字/字符串

我正在构建DSL并尝试定义一个可以在表达式中使用的自定义类CustomClass

def result = customInstance >= 100 ? 'a' : 'b'
if (customInstance == 'hello') {...}

当您的类定义了equals并同时实现Comparable(定义compareTo)时,Groovy不会调用==.

相反,Groovy调用具有分支逻辑的compareToWithEqualityCheck.除非您的自定义DSL类可以从String或Number分配,否则上面的示例将不会调用自定义compareTo.

您无法使用String扩展CustomClass.
我觉得我错过了什么.希望你能帮我弄清楚如何实现一个像我上面所示的简单案例.

最佳答案 以下是一个简短的回答:您可以为CustomClass扩展GString.然后在两种情况下都会调用它的compareTo方法 – 当你检查相等性和实际比较时.

编辑:考虑以下情况,它将适用于1和2,但不适用于3.

customInstance >= 100      // case 1
customInstance == 'hallo'  // case 2
customInstance == 10       // case 3

现在我将解释我从Groovy的ScriptBytecodeAdapter和DefaultTypeTransformation中的实现中理解的内容.

对于==运算符,如果实现了Comparable(并且没有简单标识),它会尝试使用接口方法compareTo,因此使用与其他比较运算符相同的逻辑.只有在没有实现Comparable的情况下,它才会尝试根据某些智能类型调整确定相等性,并且最终比率会回落到调用equals方法.这发生在DefaultTypeTransformation.compareEqual#L603-L608

对于所有其他比较运算符,例如> =,Groovy委托compareToWithEqualityCheck方法.现在调用此方法时将equalityCheckOnly标志设置为false,而对于第一种情况,当调用源自==运算符时,将其设置为true.如果是数字,字符或字符串,还会根据左侧的类型发生一些Groovy智能.如果不适用,则最终在DefaultTypeTransformation.compareToWithEqualityCheck#L584-L586中调用compareTo方法.

现在,只有当这种情况发生时

!equalityCheckOnly || left.getClass().isAssignableFrom(right.getClass())
  || (right.getClass() != Object.class && right.getClass().isAssignableFrom(left.getClass())) //GROOVY-4046
  || (left instanceof GString && right instanceof String)

对于equalityCheckOnly的情况有一些限制,因此当我们来自==运算符时.虽然我无法解释所有这些,但我认为这些是为了防止在特定情况下抛出异常,例如评论中提到的问题.

为简洁起见,我在上面省略了在ScriptBytecodeAdapter中预先处理并且如果左侧和右侧都是相同类型以及Integer,Double或Long之一,则会立即委托为equals的情况.

点赞