generics - 如何使用多个参数化类型(使用 where 子句)以便我可以使用任一参数
问题描述
有没有办法告诉 kotlin 这个函数接受的类型 T 可能是 Long OR Int 或 String?
在这个例子map: Map<String, T>?
中可以接收一个 Map。
import android.content.Context
import android.content.Intent
const val KEY_COMMAND = "KEY_COMMAND"
const val KEY_EXTRA = "KEY_EXTRA"
class IntentBuilder {
companion object {
fun <T> getIntent(
context: Context,
clazz: Class<Any>,
command: Command,
map: Map<String, T>?
): Intent where T : Long {
val intent = Intent(context, clazz)
intent.putExtra(KEY_COMMAND, command)
if (map != null) {
map.entries.forEach {
intent.putExtra(it.key, it.value)
}
}
}
}
}
我想允许这个函数接收一个Map <String, Long>
orMap<String, String>
值。
所以intent.putExtra(it.key, it.value)
不会出现编译错误。
我认为可以使用 where 来做到这一点。
解决方案
getIntent
您可以通过使用私有构造函数封装在泛型类中并提供其实例参数化可接受类型来解决您的问题:
class IntentFactory<in T> private constructor() {
companion object {
val int = IntentFactory<Int>()
val long = IntentFactory<Long>()
val string = IntentFactory<String>()
}
fun getIntent(
context: Context,
clazz: Class<*>,
command: Command,
map: Map<String, T>?
): Intent {
// your implementation
}
}
用例:
IntentFactory.int.getIntent(
context,
clazz,
command,
mapOf("1" to 1)
)
UPD:
如果您的意思是 map 可以同时包含Int
,Long
和String
值,您应该创建一个包装这些类型的对象的类。我还建议向key
此类添加属性:
class IntentExtra<out T> private constructor(val key: String, val value: T) {
companion object {
operator fun invoke(key: String, value: Int) = IntentExtra(key, value)
operator fun invoke(key: String, value: Long) = IntentExtra(key, value)
operator fun invoke(key: String, value: String) = IntentExtra(key, value)
}
}
现在您的函数可以接受List<IntentExtra<*>>
:
fun getIntent(
context: Context,
clazz: Class<*>,
command: Command,
extra: List<IntentExtra<*>>?
): Intent {
// your implementation
}
用例:
IntentFactory.getIntent(
context,
clazz,
command,
listOf(
IntentExtra("int", 1),
IntentExtra("long", 1L),
IntentExtra("string", "s")
)
)
您还可以创建一个 DSL 以使客户端代码更简洁:
class IntentExtraDSL(private val intent: Intent) {
private fun extra(key: String, value: Any) {
intent.putExtra(key, value)
}
infix fun String.extra(value: Int) = extra(this, value)
infix fun String.extra(value: Long) = extra(this, value)
infix fun String.extra(value: String) = extra(this, value)
}
fun getIntent(
context: Context,
clazz: Class<*>,
command: Command,
extra: IntentExtraDSL.() -> Unit
): Intent {
val intent = Intent(context, clazz)
intent.putExtra(KEY_COMMAND, command)
IntentExtraDSL(intent).extra()
return intent
}
用例:
IntentFactory.getIntent(
context,
clazz,
command
) {
"int" extra 1
"long" extra 1L
"string" extra "s"
}
推荐阅读
- python - Discord.py 错误 discord.ext.commands.errors.CommandInvokeError:命令引发异常:TypeError:'dict' 对象不可调用
- typescript - 使用泛型获取我的小 compose 函数的类型化结果
- spring - 更新多个购物车商品数量。Spring Boot - Thymeleaf
- python - 如何将 CSS 文件链接到 Django 的 pdf.html 文件,修复 FileNotFoundError
- javascript - Vanilla JS如何更新本地存储数组中的值?
- java - Gradle 同步失败:不支持的方法:SyncIssue.getMultiLineMessage()。(安卓工作室)
- typescript - Typescript - 将两个动态处理的枚举合并为一个
- java - Tomcat 错误 - 状态码 404,资源不可用
- xml - Open XML 仍然是一回事吗
- android - Firebase 电话身份验证已启用,但应用程序一直说它已禁用;我能做些什么?