在kotlin中使用lambda中的多个泛型类型

时间:2018-05-23 01:50:35

标签: generics lambda kotlin

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>

关于如何传递多个泛型并返回泛型类型的示例的任何建议?

非常感谢,

3 个答案:

答案 0 :(得分:9)

你是对的:正如您使用的那样,泛型允许使用任何类型,即使是那些不提供+运算符的类型。指定类型为Number很容易。但是,它不会使函数编译:

fun <T : Number> onScanExt(): (T, T) -> T = { 
    num1, num2 -> num1 + num2
}

(请注意,您的示例中不需要第二个类型参数R。)

问题再次出现,即使Number合同中也不包含+运营商。这些是针对特定类型IntDouble等直接定义的(参见source)。

诸如Kotlin之类的强类型语言将不允许这样的实现。

答案 1 :(得分:6)

用签名

写任何东西都没有合理的方法
fun <T, R> onScanExt(): (T, T) -> R

因为它表示来电者可以选择任意TR,然后您需要从两个R获得T;但TR之间没有任何关系,因此您无法使用T

你可以编译:例如使用someExpression as Rthrow SomeException(),或无限循环。但这些都不是真的有用。

一般来说(C ++是一个很大的例外;它的模板工作方式不同),通用方法必须:

  1. 处理所有类型(或者,在Java中,除了基元之外的所有类型)。所以它只能使用所有类型的可用操作,而且这些操作很少。具有两个类型参数的示例是

    fun <T1, T2> apply(f: T1 -> T2, x: T1) = f(x)
    
  2. 处理满足某些约束条件的所有类型。不同的语言允许不同的约束;例如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!