kotlin - Kotlin: Generic type functions: Out-projected type ... 禁止使用
问题描述
给定一个类:
class Data<T>{
fun get(): T = Something as T
fun update(item: T) { }
}
如何做这样的事情?
fun alterData(d: Data<*>){
d.update(d.get())
}
函数“alterData”不会编译:
Out-projected type 'Data<*>' 禁止使用 'fun update(item: T)'
更新: alterData() 的调用者不知道类型,所以这是不可能的:
fun <T>alterData(d: Data<T>){
d.update(d.get())
}
我发现绕过这个限制的唯一方法是在类中编写方法,但这会破坏抽象
解决方案
*
基本上意味着你不知道T
在这种情况下是什么类型,所以它可以是任何东西。
因为你已经定义d
为Data<*>
调用d.get()
返回Any?
。编译器不知道d
包含什么类型的数据。因此,您必须期待任何对 有效的东西T
,包括null
.
因为您已经定义d
为Data<*>
calld.update(…)
只接受Nothing
,即根本没有价值。编译器无法知道d
允许接收什么类型的数据。因此它不能接受任何东西,因为它在这里可能有效也可能无效。
您想告诉编译器的是d
(出投影)和进出(投影)之间的关系d
:
fun <T> alterData(d: Data<T>) {
d.update(d.get())
}
现在编译器知道(通过)输出的d
内容.get()
与您放入d
(通过.update(…)
)的内容相同。在这两种情况下,该类型都称为T
.
请注意,“类型参数”T
不必与您的Data<T>
声明具有相同的名称。以下内容同样有效地表明了这种关系:
fun <Something> alterData(d: Data<Something>) {
d.update(d.get())
}
如果您进一步分解代码,可能会更容易理解:
fun alterData(d: Data<*>) {
// `value` is of type `Any?` because we don't know `T` of `Data`
val value = d.get()
// `update` rejects `Any?` b/c we don't know `T` and it may not be valid
d.update(value)
}
fun <Something> alterData(d: Data<Something>) {
// `value` is of type `Something` b/c we know that `T` of `Data` is `Something`
val value = d.get()
// `update` accepts `Something` b/c we know `T` is `Something`
d.update(value)
}
在你的情况下,调用者和被调用者(alterData
)都不知道你的实际类型,T
你必须告诉编译器通过使用强制转换来忽略编译时类型安全。
您可以在调用者或被调用者中执行此操作。更有意义的地方取决于实际用例。通常调用者比被调用者更了解上下文和可能的类型T
,因此在那里执行强制转换是有意义的。
fun foo(d: Data<*>) {
// ignore all type safety for `T`
alterData(d as Data<Any?>)
}
被调用者alterData
立即将它从一个Data
实例 ( d
) 接收到的值传递回同一实例。在这种情况下,可以安全地假设这永远不会出错,因为您对class Data
. 如果是这种情况,那么您可以安全地在alterData
函数中执行案例:
fun alterData(d: Data<*>){
// ignore type safety and allow any value to be passed into `d`
(d as Data<Any?>).update(d.get())
}
这两种方法都会引发编译器警告,您可以使用@Suppress("UNCHECKED_CAST")
.
推荐阅读
- python-3.x - 使用 Scikit-Learn API 时如何调整 XGBoost 分类器中的概率阈值
- wpf - 在 WPF 中向 ComboBox 添加文本和值
- azure - 是否可以将 Azure Blob 存储容器 IP 列入白名单以仅接受来自特定 Azure Functions 的请求
- php - 登录成功后PHP重定向失败
- amazon-web-services - 如何在 CodePipeline 中限制 CodeBuild,使其仅在需要时构建?
- javascript - html输入文本“密码框”和按钮检查密码是否正确显示“OK”或“ERROR”
- symfony4 - 如何在 symfony 中管理角色
- javascript - 使用 express Validator 的 .equals() 进行验证
- google-bigquery - 在 Cloud Data Prep 中使用带有 BigQuery 参数的数据集?
- python - python ControlScripts/control.py /dev/tty.PathToUsbDevice - 找不到正确的路径