问:gradle 里 def 方法为什么不能引用 def 的变量?
为什么引用不到
1def x = 1
2
3def fun() { println x }
4fun()
5
6android { println x }
如上图所示,fun 无法引用 x,会报错。但 android 闭包中的 x 却能打印出来。这是为什么呢?
1def x = 1
2
3def fun1() { println x }
4
5fun1()
6
7def fun2(Closure closure) { closure() }
8
9fun2 { println x }
运行上面的文件,会报错 Caught: groovy.lang.MissingPropertyException: No such property: x for class: MyGroovy。注释掉 fun1() 后,就可以正常运行。由于在工具栏上的配置中运行时没有生成 build 文件夹,我们手动执行下 compileGroovy 方法,在 app/build/classes/groovy/main 查看编译后的 MyGroovy.class。核心代码是这样的:
1public Object run() {
2 Reference x = new Reference(1);
3 this.fun1();
4 class _run_closure1 extends Closure implements GeneratedClosure {
5 }
6 return var1[2].callCurrent(this, new _run_closure1(this, x));
7}
8
9public Object fun1() {
10 CallSite[] var1 = $getCallSiteArray();
11 return var1[3].callCurrent(this, var1[4].callGroovyObjectGetProperty(this));
12}
13
14public Object fun2(Closure closure) {
15 CallSite[] var2 = $getCallSiteArray();
16 return var2[5].call(closure);
17}
run() 方法就是 groovy 脚本执行的方法。可以看出,它先生成了一个 x 的引用,然后调用 fun1、fun2。
fun1 调用时,在它的内部执行了 callGroovyObjectGetProperty 方法,在获取 Groovy 对象的属性。也就是在属性中去寻找 x。
fun2 调用时,是将 x 直接传入了闭包的对象。
因为 x 并不是一个属性,只是一个临时变量,所以 fun1 获取不到,而 fun2 能获取到。
既然是因为属性中没有 x,那我们把 x 加入到属性中就可以了。看一下 gradle 中一个 project 的属性有哪些。一个 project 有 6 种属性的作用域:
Project 自己。
这个 project 的附加属性(通过 ext 定义)。
通过插件加入到 Project 的 extensions。
通过插件加入到 Project 的 convention 属性。
这个 project 里的 task。
这个 project 的父 project,递归到根 project。从这里访问到的都是只读的。
所以,将 x 的定义放在 ext 中即可:
1ext { x = 1 } // 或者 ext.x = 1
2
3def fun() { println x }
4
5fun()
现在能正常打印出 x 的值。另外,使用 Script 的 binding 对象也可以实现属性中添加 x。
1binding.setVariable("x", 1)
2def fun() { println x }
3fun()
点击左下角阅读原文查看历史经典技术问题汇总,看完顺手走一波PYQ呀~