【问题标题】:Kotlin using getter for read-only variableKotlin 使用 getter 作为只读变量
【发布时间】:2018-12-24 06:57:58
【问题描述】:
我们对 val 变量使用 get() 有什么原因吗?
我认为下面的代码是不必要的
private val context: Context get() = ApplicationProvider.getApplicationContext<Context>()
所以我把它改成了
private val context: Context = ApplicationProvider.getApplicationContext<Context>()
将 get() 用于只读变量会有什么不同?
【问题讨论】:
标签:
android
kotlin
mockito
robolectric
【解决方案1】:
您正在处理声明属性的两种不同方式:
带有支持字段的属性
如果你声明一个属性context 并像这样分配它:
private val context: Context = ApplicationProvider.getApplicationContext<Context>()
你创建了一个property with backing field。
ApplicationProvider.getApplicationContext<Context>() 在类被实例化时被评估一次。由于 context 是不可变的 (val) 每次返回相同的值(由函数调用分配)。
没有支持字段的属性
如果你这样声明context
private val context: Context get() = ApplicationProvider.getApplicationContext<Context>()
您创建了一个没有支持字段的属性。每次访问 context 时都会评估 ApplicationProvider.getApplicationContext<Context>()。 getter 返回的值可以根据函数的转发调用是否返回不同的值而改变。
使用什么?
因此,这取决于您的用例,但在这种特殊情况下,我建议您使用不带支持字段变体的属性,原因有两个:
- 你不能确定
ApplicationProvider.getApplicationContext<Context>() 总是返回相同的值,至少文档没有明确提到这一点
- 转发函数调用不会对性能产生重大影响
【解决方案2】:
对于 getter 不需要定义 get() 但 setter case set 是必需的。
从 Kotlin 1.1 开始,如果可以从 getter 中推断出属性类型,则可以省略:
val isEmpty get() = this.size == 0 // has type Boolean
如果您需要更改访问器的可见性或对其进行注释,但不需要更改默认实现,则可以定义访问器而不定义其主体:
var setterVisibility: String = "abc"
private set // the setter is private and has the default implementation
var setterVisibility: String = "abc"
private set // the setter is private and has the default implementation
更多详情请参考Properties and Fields
【解决方案3】:
IntelliJ Amiya 在评论中提供的链接包含所有必要的信息,但特别是要回答您的问题:
get() = ... 每次被访问时都会调用ApplicationProvider.getApplicationContext<Context>();只是= ... 会调用一次并存储,然后在访问时返回存储的值。您想要哪一个或它们是否有效等效(例如,主体总是返回相同的值并且足够快)取决于上下文。