这里要看到的“问题”是Groovy中的(隐式)扩展运算符。
表达式cars*.make
等价于cars.collect{ it.make }
。当引用的属性不是包含列表的属性时,Groovy 的 GPath 表示法允许使用快捷方式,在这种情况下,它会自动扩展。在前面提到的情况下,cars.make
可以使用表达式,但通常建议保留显式点运算符。
(那里的例子谈到了 GPath,但对于列表、地图等也是如此)
lock1.unlock()
在这种情况下也是如此lock1*.unlock()
。(动态)Groovy 会看到,列表中没有unlock()
方法,只是扇出。
至于“所以很可能,lock1 是类锁的对象”,会让你做噩梦。不要猜测 - 找出答案。您可以println(lock1.inspect())
了解详细信息,希望该类的作者有远见,添加了一个有用的toString()
方法。检查文档,函数返回的内容,您分配locks1
的内容。使用工具,告诉你类型(IDE,调试器,...)。
对于开发人员来说,更好的命名有助于:
// BAD naming
def locks1 = smartThings.getAll(Lock, clientId)
// better naming, add the type if it helps you or your IDE
Collection<Lock> allLocks = smartThings.getAll(Lock, clientId)
现在,如果你打电话给allLocks.lock()
,事情就更明显了。
为了防止隐式传播运算符,您可以在 groovy 脚本中使用静态编译。例如:
class Lock {
def lock() { println "lock" }
def unlock() { println "unlock" }
}
@groovy.transform.CompileStatic
class X {
public static main() {
[new Lock()].lock()
}
}
这不会编译:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
x.groovy: 9: [Static type checking] - Cannot find matching method java.util.List#lock(). Please check if the declared type is correct and if the method exists.
@ line 9, column 3.
[new Lock()].lock()
^
1 error
使用显式扩展运算符 ( [new Lock()]*.lock()
) 进行编译。