针对CustomClass和数字/字符串进行Groovy compareTo

时间:2018-12-15 23:18:09

标签: groovy dsl

我正在构建DSL并尝试定义一个自定义类CustomClass,您可以在类似

的表达式中使用它
def result = customInstance >= 100 ? 'a' : 'b'
if (customInstance == 'hello') {...}

当您的类同时定义==并实现equals(定义{{​​1}})时,Groovy不会调用Comparable

相反,Groovy调用具有分支逻辑的compareTo。并且除非您的自定义DSL类可从compareToWithEqualityCheckString分配,否则您的自定义Number不会在上述示例中被调用。

您不能用compareTo扩展CustomClass。 我觉得我想念什么。希望您能帮助我弄清楚如何实现如上所示的简单案例。

1 个答案:

答案 0 :(得分:1)

以下是一个简短的答案:您可以将GString扩展为CustomClass。然后在两种情况下都会调用其compareTo方法-在检查是否相等以及实际比较时。

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

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

现在,我将解释我从Groovy的ScriptBytecodeAdapterDefaultTypeTransformation的实现中所了解的内容。

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

对于所有其他比较运算符,例如>=,Groovy委托了compareToWithEqualityCheck方法。现在,在将equalityCheckOnly标志设置为false的情况下调用此方法,而在第一种情况下,其调用源自==运算符时将其设置为true。同样,根据左侧的类型(如果是Number,Character或String),会出现一些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中预先处理并立即委托给equals的情况整数,双精度或长整数。