我正在kotlin中創建資料類
data class User(val mountOptions: MountOptions)
{
constructor(mountOptions: MountOptions, detailsOne: OneDetails): this(mountOptions)
constructor(mountOptions: MountOptions, detailsTwo: TwoDetails): this(mountOptions)
}
data class MountOptions(val a: String, val b: String)
data class OneDetails(val c: Int)
data class TwoDetails(val c: String)
在我的主要功能中,我可以這樣訪問物件:
fun anotherCaller(val user: User){
println(user.mountOptions.a)
println(user.mountOptions.b)
// can we do something like this? doesn't seem to work
// println(user.detailsOne.c) // doesn't work
// println(user.detailsTwo.c) // doesn't work
}
fun main(){
...
...
val mt = MountOptions("foo", "bar")
val one = OneDetails(1)
val two = TwoDetails("2")
when(System.getenv("ENVVV")){
"1" -> anotherCaller(User(mt, one))
"2" -> anotherCaller(User(mt, two))
}
}
我的問題是我無法訪問detailsOne或detailsTwo。
我想要做的是,創建一個嵌套data class的頂級data class是將被訪問的常見專案,并且在建構式中,有適合某些情況的附加專案。
有任何想法嗎?
抱歉,我認為舉一個較小的例子可能會更容易,但我意識到它并不能清楚地解釋問題。我已經用一個更準確的例子來編輯我的問題,以說明我想要實作的目標。
uj5u.com熱心網友回復:
在 Kotlin 中,您不需要單獨的建構式來定義可選的建構式引數。您可以使用默認值在單個建構式中將它們全部定義或使它們可以為空,如下所示:
data class User(val name: String, val age: Int, val size: String = "M")
fun main(){
val x = User("foo", 5, "L")
val y = User("foo", 5)
println(x.size) // "L" from call site
println(y.size) // "M" from default param
}
uj5u.com熱心網友回復:
您不能訪問大小變數,因為這是來自輔助構造,但我們有替代變體。
data class User(var name: String, var age: Int) {
var size: String
init {
size = "size"
}
constructor(name: String, age: Int, size: String) : this(name, age) {
this.size = size
}
}
uj5u.com熱心網友回復:
簡而言之,您希望擁有一個可以作為有限數量選項之一的屬性。這可以使用泛型或密封繼承來解決。
泛型
在這里,我添加了一個MountDetails帶有通用引數的介面T。有一個屬性 ,val c它的型別是T。
data class User(
val mountOptions: MountOptions,
val mountDetails: MountDetails<*>,
)
data class MountOptions(
val a: String,
val b: String
)
interface MountDetails<T : Any> {
val c: T
}
data class MountOneDetails(override val c: Int) : MountDetails<Int>
data class MountTwoDetails(override val c: String) : MountDetails<String>
因為實作MountDetails(MountOneDetails和MountTwoDetails) 指定了或的型別,所以總是可以訪問T。IntStringval c
fun anotherCaller(user: User) {
println(user.mountOptions.a)
println(user.mountOptions.b)
println(user.mountDetails)
}
fun main() {
val mt = MountOptions("foo", "bar")
val mountOneDetails = MountOneDetails(111)
anotherCaller(User(mt, mountOneDetails))
val mountTwoDetails = MountTwoDetails("mount two")
anotherCaller(User(mt, mountTwoDetails))
}
輸出:
foo
bar
MountOneDetails(c=111)
foo
bar
MountTwoDetails(c=mount two)
不過,泛型也有缺點。如果有很多泛型引數會很混亂,并且由于型別擦除,在運行時很難確定類的型別。
密封繼承
由于您只有有限數量的掛載細節,因此更簡潔的解決方案是密封類和介面。
data class User(val mountOptions: MountOptions)
sealed interface MountOptions {
val a: String
val b: String
}
data class MountOneOptions(
override val a: String,
override val b: String,
val integerData: Int,
) : MountOptions
data class MountTwoOptions(
override val a: String,
override val b: String,
val stringData: String,
) : MountOptions
這里的好處是類更少,型別更具體。添加或洗掉額外的掛載細節也很容易,任何詳盡的when陳述句都會導致編譯器錯誤。
fun anotherCaller(user: User) {
println(user.mountOptions.a)
println(user.mountOptions.b)
// use an exhaustive when to determine the actual type
when (user.mountOptions) {
is MountOneOptions -> println(user.mountOptions.integerData)
is MountTwoOptions -> println(user.mountOptions.stringData)
// no need for an 'else' branch
}
}
fun main() {
val mountOne = MountOneOptions("foo", "bar", 111)
anotherCaller(User(mountOne))
val mountTwo = MountTwoOptions("foo", "bar", "mount two")
anotherCaller(User(mountTwo))
}
輸出:
foo
bar
111
foo
bar
mount two
uj5u.com熱心網友回復:
這實際上是 Hubert Grzeskowiak 提供的“默認值”答案,已根據您的示例進行了調整:
data class OneDetails(val c: Int)
data class TwoDetails(val c: String)
data class MountOptions(val a: String, val b: String)
data class User(
val mountOptions: MountOptions,
val detailsOne: OneDetails? = null,
val detailsTwo: TwoDetails? = null
)
fun main() {
fun anotherCaller(user: User) = println(user)
val mt = MountOptions("foo", "bar")
val one = OneDetails(1)
val two = TwoDetails("2")
val switch = "0"
when (switch) {
"0" -> anotherCaller(User(mt))
"1" -> anotherCaller(User(mt, detailsOne = one))
"2" -> anotherCaller(User(mt, detailsTwo = two))
"12" -> anotherCaller(User(mt, detailsOne = one, detailsTwo = two))
else -> throw IllegalArgumentException(switch)
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/529191.html
標籤:科特林数据类
