Dart中final变量为何随引用变量变化?三类案例解析
案例1
bool _privateBool = false; final finalBool = _privateBool; void main() { _privateBool = true; print(finalBool); ///==> true }
疑问:是否因为finalBool持有_privateBool的引用,导致_privateBool变化时finalBool也随之改变?
解答:Dart里bool是值类型,finalBool初始化时是直接复制_privateBool的当前值,并非持有引用。出现这种现象是因为Dart编译器的常量折叠优化:_privateBool是全局变量,编译器在优化时,会将finalBool的访问直接关联到_privateBool的当前值,而非固定最初的复制值,所以修改_privateBool后,finalBool的输出会跟着变化。
案例2
bool _privateBool = false; final finalBool = _privateBool; void main() { print(_privateBool.hashCode); print(finalBool.hashCode); _privateBool = true; print(finalBool); ///==> false }
疑问:此案例中,因提前调用print输出两个变量的hashCode,finalBool的值未随_privateBool变化,这一现象为何出现?
解答:提前调用finalBool.hashCode触发了finalBool的实际求值。当程序访问finalBool.hashCode时,会立即确定finalBool的具体值(此时_privateBool还是false),编译器无法再进行常量折叠优化。后续修改_privateBool时,finalBool的值已经固定,所以输出false。
案例3
bool _privateBool = false; final finalBool = _privateBool; void main() { _privateBool = true; print(_privateBool.hashCode); print(finalBool.hashCode); print(finalBool); ///==> true }
疑问:此案例中,先修改_privateBool的值再输出hashCode,finalBool的值又随_privateBool变化,原因是什么?
解答:这里先修改_privateBool为true,之后才访问finalBool.hashCode。此时编译器处理finalBool的求值时,会读取_privateBool的当前值(已经是true),finalBool的值被确定为true,后续打印自然输出true。
总结:这类现象的本质是Dart编译器的延迟求值与常量折叠优化导致的。全局变量赋值的final变量,在未被提前访问时,编译器会延迟确定其实际值,直到第一次访问;若提前访问(如调用hashCode),则会在访问时刻固定final变量的值,后续源变量的修改不会再影响它。
内容的提问来源于stack exchange,提问作者Pawan Acharya

