Koltin 1.2.30
我正在使用泛型和lambda函数。
以下工作没有通用类型
fun onScanExt(): (Int, Int) -> Int = {
num1, num2 -> num1 + num2
num1 + num2
}
但是,使用泛型:
fun <T, R> onScanExt(): (T, T) -> R = {
num1, num2 -> num1 + num2
num1 + num2
}
我想上面的代码不能正常工作,因为泛型类型可能不是Number类型,有人可以传入一个字符串,如果涉及计算,lambda将不知道如何处理String类型。< / p>
关于如何传递多个泛型并返回泛型类型的示例的任何建议?
非常感谢,
答案 0 :(得分:9)
你是对的:正如您使用的那样,泛型允许使用任何类型,即使是那些不提供+
运算符的类型。指定类型为Number
很容易。但是,它不会使函数编译:
fun <T : Number> onScanExt(): (T, T) -> T = {
num1, num2 -> num1 + num2
}
(请注意,您的示例中不需要第二个类型参数R
。)
问题再次出现,即使Number
合同中也不包含+
运营商。这些是针对特定类型Int
,Double
等直接定义的(参见source)。
诸如Kotlin之类的强类型语言将不允许这样的实现。
答案 1 :(得分:6)
用签名
写任何东西都没有合理的方法fun <T, R> onScanExt(): (T, T) -> R
因为它表示来电者可以选择任意T
和R
,然后您需要从两个R
获得T
;但T
和R
之间没有任何关系,因此您无法使用T
。
你可以编译:例如使用someExpression as R
或throw SomeException()
,或无限循环。但这些都不是真的有用。
一般来说(C ++是一个很大的例外;它的模板工作方式不同),通用方法必须:
处理所有类型(或者,在Java中,除了基元之外的所有类型)。所以它只能使用所有类型的可用操作,而且这些操作很少。具有两个类型参数的示例是
fun <T1, T2> apply(f: T1 -> T2, x: T1) = f(x)
处理满足某些约束条件的所有类型。不同的语言允许不同的约束;例如C#有一个非常大的集合,Scala具有视图和上下文边界。据我所知,Kotlin只允许upper bounds。特别是,没有任何约束表示“类型T
具有运算符+
”。所以你想要的功能不能写出来。
答案 2 :(得分:4)
对于一个工作示例,lambda主体只能调用其超类型保证存在的泛型值的操作(如您所说)。因此,一些非常通用的工作示例可能是:
fun <T> onScanExt(): (T, T) -> String = { a, b ->
a.toString() + b.toString()
}
或者:
fun <T: Comparable<T>> onScanExt(): (T, T) -> T = { a, b ->
if (a.compareTo(b) < 0) a else b
}
有趣的事实:虽然通用lambda可以从函数返回,但它们不能(通常)存储在字段或变量中:
val f = onScanExt2()
无法使用错误进行编译:
没有足够的信息来推断参数T [..]。请明确说明。
与纯功能语言(如古老的Haskell)不同,其中函数和包含函数的变量之间实际上没有这种差异。如果你喜欢它简单,那么也许尝试Haskell!