class MapBuilder<T,U> {
operator fun invoke(arg: T): MapBuilder<T, U> {
return this
}
operator fun invoke(arg: U): MapBuilder<T, U> {
return this
}
}
当然,由于JVM的限制,它不起作用。
Platform declaration clash: The following declarations have the same JVM signature (invoke(Ljava/lang/Object;)Lcom/test/tests/MapBuilder;):
operator fun invoke(arg: T): MapBuilder<T, U> defined in com.test.tests.MapBuilder
operator fun invoke(arg: U): MapBuilder<T, U> defined in com.test.tests.MapBuilder
任何想法,我该如何实现?
答案 0 :(得分:2)
这是因为冲突过多。
有效地,使用您当前的参数,T
可以等于U
。如果您熟悉重载,则应该知道这是不允许的:
fun something(x: Int){ /* foo */ }
fun something(x: Int){ /* bar */ }
但是对于一个实例,它是:
fun something(x: Int){ /* foo */ }
fun something(x: Float){ /* bar */ }
由于它们可能相同,因此将导致冲突。它怎么知道要调用哪种方法?
在整个范围内,编译器都会抱怨。如果对一个参数使用: SomeClass
,它将停止抱怨。但这是一个随机的例子:
class MapBuilder<T, U : Logger> {
operator fun invoke(arg: T): MapBuilder<T, U> {
return this
}
operator fun invoke(arg: U): MapBuilder<T, U> {
return this
}
}
fun t(){
MapBuilder<Logger, Logger>().invoke(LoggerFactory.getLogger(""))
}
invoke
将不明确。现在,只有两个相等的类型才存在问题。它使用哪个?
现在,您的MCVE非常小。我不知道你用T和U做什么。结果,我无法给您任何代码示例。但是,您需要了解以下内容:
您不能同时使用两种类型的方法,因为它们可能会发生冲突。如果使用两个相等的类型,则即使使用方差也会导致重载问题。因此,它将排除MapBuilder<Int, Int>
作为实例。
您可以使用一个方法,也可以将它们分为两个名称不同的方法。名称显示它是一个生成器,因此您可以使用withKey(T t)
和withValue(U u)
如果不通过Class<T>
和Class<U>
并进行检查,就无法直接禁止T ==U。不幸的是,即使使用require
或其他协定函数,编译器也无法理解。另外,在尝试之前,无法使用: Any
。这是默认界限。请记住,在Java中,一切都是Object
;在Kotlin中,一切都是Any
。
您可以使用@JvmName(在Jayson Minard的答案中提到)来解决此问题,但是如果与Java互操作,则将使用两个不同的方法名称。如果只使用Kotlin,可能会稍微容易一些。 Java-Kotlin互操作具有一堆@Jvm*
注释,其中大多数/全部都被in the docs覆盖。
即使使用@JvmName,它仍将允许<String, String>
,直到调用冲突的方法为止。如果无论如何要断言T!= U,则需要运行类检查。
答案 1 :(得分:2)
在未知的泛型类型下,这些方法可以有效地具有相同的签名。因此,所提供的基本情况对于JVM是不明确的。因此,您只需要给他们一个替代名称,JVM(以及Java或其他JVM语言)将从中使用它们来查看它们。您在一个或两个以上的符号上使用{
"Version":"2012-10-17",
"Statement":[{
"Sid":"AddPerm",
"Effect":"Allow",
"Principal":"*",
"Action":[
"s3:GetObject"
],
"Resource":[
"arn:aws:s3:::emergencydatascience.org/*"
]
}]
}
批注,以为其指定内部名称。这完全不会影响Kotlin,也不会影响您在Kotlin代码中使用的名称,它们将像以前一样显示它们。
@JvmName
现在,您很好,可以独立使用它们。
class MapBuilder<T,U> {
@JvmName("invokeWithT")
operator fun invoke(arg: T): MapBuilder<T, U> {
return this
}
@JvmName("InvokeWithU") // technically don't need both of these
operator fun invoke(arg: U): MapBuilder<T, U> {
return this
}
}
请注意,如果val builder = MapBuilder<String, Integer>()
builder("hi") // success!
builder(123) // success!
和T
含糊不清,则在尝试调用它们时会出现其他错误。
U
错误:(y,x)Kotlin:重载分辨率不明确:
@JvmName公共最终运算符fun invoke(arg:String):MapBuilder中定义的MapBuilder
@JvmName公共最终运算符fun invoke(arg:String):MapBuilder中定义的MapBuilder
如果您可以某种方式定义泛型,而这些泛型可能不会重叠并且属于同一类,那么您也可以解决此问题。根据所选择的实际通用参数,您可能会收到错误,但至少可以使用基本声明。 Zoe's answer中对此进行了更详细的描述。