[英]Kotlin: Generics in sealed classes
我正在嘗試使用 Kotlin 實現某種規范模式,並且我有以下代碼:
// T is the returning type for each query
sealed class Query<T> {
class ByName(val name: String): Query<List<User>>()
class ById(val name: String): Query<User>()
}
class Repository {
fun <T> find(query: Query<T>): T {
return when(query) {
is ByName -> getUsersByName(query.name)
// other query types
}
}
private fun getUsersByName(name: String): List<User> { /*...*/ }
}
但我收到一個錯誤:
Type mismatch
Expected: T
Found: List<User>
如果我將結果轉換為T
(通過添加as T
),它會編譯但我收到Unchecked cast
警告。 安全嗎?
有沒有辦法在沒有警告的情況下做到這一點?
考慮密封類型時不會考慮泛型。 例如,當編譯器分析is ByName
分支時,它不會“啊,我看到T == List<User>
在這里!”。
當您強制轉換為T
,編譯器無法生成任何代碼來檢查該強制轉換在那時是否有效,因為在運行時類型參數都被刪除,因此是“未經檢查的強制轉換”。
據我所知,演員表總是安全的,因為你事先檢查了類型。
消除警告的一種方法是內聯函數並具體化類型參數:
inline fun <reified T> find(query: Query<T>) =
when(query) {
is Query.ByName -> getUsersByName(query.name) as T
is Query.ById -> getUsersById(query.name) as T
}
這意味着getUsersByName
和getUsersById
不能再是私有的,但它們可以調用其他私有方法。
這是有效的,因為您現在正在用when
表達式替換find
每個調用(這就是“內聯”的意思),並且調用者總是知道T
是什么(因此具體化了T
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.