忽略setter并直接设置属性

我有一个类,写一个用户SharedPreferences每次它的设置:

class UserManager @Inject constructor( val prefs: SharedPreferences, val jsonAdapter: JsonAdapter ) { companion object { val USER = "user" } var user: User = User() set(value) { field = value prefs.edit().putString(USER, jsonAdapter.toJson(user)).apply() } init { val userString = prefs.getString(USER, null) if (userString != null) { user = jsonAdapter.fromJson(userString) } } } 

问题:如果用户被设置在init块中,它会调用setter,并将刚才从共享的prefs中得到的用户写入共享的prefs。

问题1:如何直接从init块设置属性?

问题2:当我定义一个自定义setter时,为什么我必须初始化用户,但是当使用默认setter时可以省略初始化?

您需要直接用正确的价值来启动房产。 你可以使用stdlib的run函数来做到这一点:

 class UserManager @Inject constructor( val prefs: SharedPreferences, val jsonAdapter: JsonAdapter ) { companion object { val USER = "user" } var user: User = run { val userString = prefs.getString(USER, null) if (userString != null) { jsonAdapter.fromJson(userString) } else { User() } } set(value) { field = value prefs.edit().putString(USER, jsonAdapter.toJson(user)).apply() } } 

在Kotlin Slack上由Ilya Ryzhenkov提出的更短的语法:

 var user: User = prefs.getString(USER, null)?.let { jsonAdapter.fromJson(it) } ?: User() set(value) { field = value prefs.edit().putString(USER, jsonAdapter.toJson(user)).apply() } 

我相信最好的解决方案是使用这里描述的“支持属性”概念: https : //kotlinlang.org/docs/reference/properties.html#backing-properties

 private var _table: Map? = null public val table: Map get() { if (_table == null) _table = HashMap() // Type parameters are inferred return _table ?: throw AssertionError("Set to null by another thread") } 

然后在构造函数中初始化支持属性,并且执行 = value而不是field = value以及将getter指向backing属性。

看看by map委托,看起来这是你想要的模式:

 class User(val map: MutableMap) { var name: String by map var age: Int by map } 

https://kotlinlang.org/docs/reference/delegated-properties.html#storing-properties-in-a-map