【问题标题】:What's going on with this generic function?这个通用函数是怎么回事?
【发布时间】:2015-11-23 21:40:40
【问题描述】:

对不起,笼统的标题,没有例子很难描述问题。

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

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

这是一个使用上述功能的例子:

test(expect: 100) { 10 * 10 } // prints "OK"
test(expect: 1000) { 10 * 10 } // prints "Expected: 1000, Actual: 100"

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

let e = 100
test(expect: e) { e } // prints "OK"

到目前为止一切顺利,一切正常(没有双关语)。

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

test(expect: [1, 2]) { [1, 2] } // prints "OK"

再一次,事情解决了。

但现在我们试试这个:

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

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

Playground 正确推断出a 的类型为[Int],那么() -&gt; _ 的期望从何而来?

尝试上一个示例的一系列变体:

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 }

它们都会导致相同的问题。出于某种原因,Swift 似乎认为该函数需要 () -&gt; _

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

let a = [1, 2]
[1, 2] == [1, 2]
a == a

我认为我非常了解泛型,但我完全被这个难住了。这是 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]"

【问题讨论】:

  • 答案与stackoverflow.com/a/33732669/669586 相同,但我不确定是否应该将其作为副本关闭。
  • @Sulthan 这绝对是同一个问题的根源,但是通过函数执行此操作的事实使问题有点模糊,我认为它值得独立存在。另外,部分问题是如何进行这项工作,对问题的编辑也解决了这个问题。
  • 作为我上面“解决方案”的旁注。将test() 的实现限制为SequenceType 可能是个坏主意,因为拥有无限序列是有效的,因此您不想尝试遍历所有序列。 CollectionType 会更合适。
  • 使用泛型函数相对于简单的 == 运算符有什么优势?我没有看到任何...都返回 Bool 值并且您的函数仍在内部使用 == 运算符
  • @user3441734 最好将有问题的代码提炼成最小的可演示示例,这通常会导致示例被人为设计。在这种情况下,我对该函数的实际实现实际上多次运行传入的闭包,为每次运行计时,取平均值,将结果与预期值进行比较,并在过程中记录一些日志。

标签: swift generics swift2


【解决方案1】:

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

【讨论】:

  • 就是这样!哇,这一直困扰着我一段时间!谢谢!
  • 实际上,玩这个更多.. 你确定这是将它转换为 NSArray 吗?如果我删除 import Foundation 我不能再使用 NSArray,但 [1,2,3] == [1,2,3] 仍然可以工作,所以必须进行其他操作。
  • @vopilif 为具有Element: Equatable 的数组定义了==。这并不意味着 Array 实现了Equatable
猜你喜欢
  • 1970-01-01
  • 2011-09-26
  • 2014-11-08
  • 2013-07-28
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 2011-06-28
  • 2020-04-03
相关资源
最近更新 更多