我來自 Java,是 Kotlin 的新手。我正在嘗試為單元測驗目的創建宣告性 DSL。這是我嘗試創建通用構建器方法以使用宣告性語法構造任何模型物件。
fun <T> having(t: Class<T>) = object {
infix fun with(fn: T.() -> Unit) = t.newInstance().apply(fn)
}
fun test() {
having(Pizza::class.java) with {
size = Size.NORMAL
cheese = Cheese.MOZARELLA
}
}
但是,該having函式回傳Any帶有未決議的函式參考的型別with。我可以將匿名物件提取到它自己的類中以使其編譯,但這會讓人覺得多余。是否可以使用回傳object實體的函式進行型別推斷?
另外,我不確定我是否在這里以慣用的方式使用泛型。
uj5u.com熱心網友回復:
究其原因,having因為被推斷函式的回傳型別Any是解釋我的答案在這里。基本上,您必須 makehaving private才能使其推斷出所需的回傳型別。顯然,這對于單元測驗 DSL 來說不是一個可行的解決方案,它會被其他檔案中的代碼使用。
您可以考慮洗掉單詞having,并直接將其宣告with為擴展/中綴函式KClass。
擴展功能:
fun <T: Any> KClass<T>.with(fn: T.() -> Unit) = this.createInstance().apply(fn)
// ...
Pizza::class.with {
size = Size.NORMAL
cheese = Cheese.MOZZARELLA
}
中綴函式:
infix fun <T: Any> KClass<T>.with(fn: T.() -> Unit) = this.createInstance().apply(fn)
fun main() {
Pizza::class with {
size = Size.NORMAL
cheese = Cheese.MOZZARELLA
}
}
uj5u.com熱心網友回復:
object您可以回傳一個包裝物件,而不是回傳未指定的型別,該物件宣告with函式并包含原始類物件。
通過這種方式,您可以獲得型別安全,同時保留您having風格的 DSL。
data class WrappedInstance<T>(val data: T) {
infix fun with(applyFn: T.() -> Unit): T = data.also(applyFn)
}
fun <T : Any> having(kClass: KClass<T>): WrappedInstance<T> =
WrappedInstance(kClass.createInstance())
使用它,看起來像這樣:
data class Pizza(var size: Int = 1, var cheese: Int = 1)
fun test() {
val pizza: Pizza = having(Pizza::class) with {
size = 3
cheese = 5
}
println(pizza.size)
println(pizza.cheese)
}
請注意,這和您的原始方法都有一個警告。它們僅適用于具有建構式的類,不需要任何引數。
請參閱以下檔案KClass<T>.createInstance():
創建類的一個新實體,呼叫一個沒有引數或所有引數都是可選的建構式(參見 KParameter.isOptional)。如果沒有或很多這樣的建構式,則拋出例外。
當不需要havingDSL 部分時,請查看@Sweeper 的解決方案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/371506.html
