0

我有 2 个重载函数,我正在尝试使用它们在调用者中使用泛型的签名来调用它们。例如:

func sum(_ i: Int, _ s: Int){
print("sum \(i+s)")
}

func sum(_ i: String, _ s: Int){
var res: String="";
for _ in 1...s{
    res += i
}
print("Repeat \(res)")
}

func sumCaller<T>(_ f: T){
print(type(of: f)) // compiler prints the value is function (Int,Int)->Void !!!
}

sumCaller(sum as (Int, Int)->Void)

这里一切都很好。但是当我试图像这样打电话fsumCaller

func sumCaller<T>(_ f: T){
print(type(of: f)) //compiler prints the value is function (Int,Int)->Void !!!
f(1,3)
}

编译器抛出错误:

error: testing.playground:68:5: error: cannot call value of non-function type 'T' f(1,3)

但它仍然是我作为sumCaller参数传递的同一个函数。拜托,有人可以解释我的错误吗?

4

3 回答 3

1

我不确定你的目标是什么,但下面的代码“做某事”。希望这是您正在寻找的:

func sum(_ i: Int, _ s: Int){
    print("sum \(i+s)")
}

func sum(_ i: String, _ s: Int){
    var res: String="";
    for _ in 1...s{
        res += i
    }
    print("Repeat \(res)")
}

func sumCaller<A, B>(_ f: (A, B) -> Void, a: A, b: B) {
    print(type(of: f)) // compiler prints the value is function (Int,Int)->Void !!!
    f(a, b)
}

sumCaller(sum, a: 2, b: 3)
sumCaller(sum, a: "Test", b: 3)
于 2020-11-23T12:24:10.293 回答
1

如您所知,当您使用泛型函数时,T它是占位符类型名称而不是实际类型名称。占位符可以是任何类型,包括StringDictionaryInt等。只有在调用函数时,才会插入实际类型来代替T。这个用实际类型替换泛型类型的过程称为专门化或解析泛型。为了解析泛型,编译器要求对这T是什么没有歧义,否则它会抛出一个错误,这就是这里发生的事情。

当您查看此代码时:

func sumCaller<T>(_ f: T){
   print(type(of: f)) //compiler prints the value is function (Int,Int)->Void !!!
   f(1,3)
}

没有机会调用此函数并将其T替换为实际类型,这意味着T它仍然是一个占位符并且可以是任何类型。例如,f可能是String类型,这意味着f(1,3)等于String(1,3),这没有意义。编译器让您知道对于可能是什么仍然存在歧义T

于 2020-11-23T14:58:35.057 回答
0

我认为,如果您忘记 T 和泛型,只考虑编译器知道的内容与运行时的真实情况,那么最容易理解这一点。

首先考虑以下代码:

func myFunc(_ : Int, _ : Int) { print("it worked") }
let f : Any = myFunc
print(type(of: f)) // (Int, Int) -> ()

该代码编译并运行,正如我的评论所示,打印(Int, Int) -> (). 但这是运行时打印。当应用程序运行时,运行时会查看f 实际情况并将其打印出来。

但在代码运行很久之前,它必须编译. 编译器只知道事物是如何从外部输入的。因此,就编译器而言,f是 Any ,仅此而已。知道这f是一个函数,但编译器不知道!

所以,现在我们将在我们的代码中添加一行,它不会再编译了:

func myFunc(_ : Int, _ : Int) { print("it worked") }
let f : Any = myFunc
print(type(of: f))
f(1,2) // cannot call value of non-function type 'Any'

你有看到?编译器不知道里面 有一个函数f。它只看到f,这是一个 Any。直到运行时才f具有可以检查的真正价值。

我们可以通过强制编译器相信这将在运行时变成一个函数来解决这个问题:

func myFunc(_ : Int, _ : Int) { print("it worked") }
let f : Any = myFunc
print(type(of: f)) // (Int, Int) -> ()
(f as! (Int,Int) -> ())(1,2) // it worked

compile 编译运行函数被成功调用,正如我们所知,因为它打印出"it worked".

发生了什么?我们对as!(强制转换)的使用告诉编译器抛弃它自己的信念,只是盲目地接受我们的断言,即当应用程序运行时,f它将变成一个函数。所以编译器让我们假装这是真的,并消除了它的反对意见,让我们运行代码。我们说的是实话,所以我们的代码也能成功运行。

但是如果我们撒了谎——如果f是其他类型的事情——那么编译器仍然不会反对,但我们的应用程序会在转换时崩溃as!

func myFunc(_ : Int, _ : Int) { print("it worked") }
let f : Any = 1
print(type(of: f)) // (Int, Int) -> ()
(f as! (Int,Int) -> ())(1,2) // crash
于 2020-11-23T15:24:40.283 回答