这个通用功能发生了什么?

vop*_*lif 7 generics swift swift2

对于通用标题很抱歉,如果没有示例,很难描述问题.

假设我定义了以下限制为Equatable类型的泛型函数:

func test<T: Equatable>(expect expected: T, run: () -> T) {
    let value = run()
    if value == expected {
        print("OK")
    } else {
        print("Expected: \(expected), Actual: \(value)")
    }
}
Run Code Online (Sandbox Code Playgroud)

这是使用所述函数的示例:

test(expect: 100) { 10 * 10 } // prints "OK"
test(expect: 1000) { 10 * 10 } // prints "Expected: 1000, Actual: 100"
Run Code Online (Sandbox Code Playgroud)

当然,我可以存储值而不是使用文字:

let e = 100
test(expect: e) { e } // prints "OK"
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,一切都按预期工作(没有双关语意).

现在让我们用一个数组来尝试:

test(expect: [1, 2]) { [1, 2] } // prints "OK"
Run Code Online (Sandbox Code Playgroud)

事情再次成功.

但现在我们尝试这个:

let a = [1, 2]
test(expect: a) { a } // error: cannot convert value of type '() -> [Int]' to expected argument type '() -> _'
Run Code Online (Sandbox Code Playgroud)

所以我一直在努力的问题是:为什么这不起作用?

游乐场正确推断的类型a[Int],所以哪里的期望() -> _从何而来?

尝试最后一个例子的一堆变体:

test(expect: a) { return a }
test(expect: a) { return a as [Int] }
test(expect: a as [Int]) { return a as [Int] }
test(expect: [1, 2]) { a }
test(expect: [1, 2] as [Int]) { a }
Run Code Online (Sandbox Code Playgroud)

它们都会导致同样的问题.出于某种原因,Swift似乎认为该功能需要() -> _.

所以也许只是因为数组不是Equatable,但这有效:

let a = [1, 2]
[1, 2] == [1, 2]
a == a
Run Code Online (Sandbox Code Playgroud)

我以为我非常了解泛型,我完全被这个难过了.这是Swift中的错误还是我定义的错误test()?甚至可以实现目标吗?

解决方案

感谢@ Sulthan在下面给出的答案,我能够编写此函数的另一个版本来处理数组大小写(以及任何SequenceType相关问题):

public func test<T: SequenceType where T.Generator.Element: Equatable>(expect expected: T, run: () -> T) {
    let result = run()
    // Note: zip() will stop at the shorter array, so this implementation isn't correct, don't use it (it will incorrectly end up saying [1] == [1,2]). This code is just here to demonstrate the function's generic constraint.
    let eq = zip(expected, result).filter(!=).isEmpty
    if eq {
        print("OK")
    } else {
        print("Expected: \(expected), Actual: \(result)")
    }
}

let a: [Int] = [1, 2]
test(expect: [1,2]) { a } // prints "OK"
test(expect: [1,3]) { a } // prints "Expected: [1, 3], Actual: [1, 2]"
Run Code Online (Sandbox Code Playgroud)

Sul*_*han 5

数组不会自动符合Equatable,即使它们的值是Equatable.但是,当您直接使用数组文字时,编译器会尝试匹配该类型并将数组转换为NSArray符合的数组Equatable.