Swift 通用函数在测试中不编译

Swift generic function does not compile in testing

我在 Swift 中编译测试用例时遇到问题。看起来编译器正在丢失有关模板类型的信息,但其他通用方法工作正常。我错过了什么?

public class MatchNorm {

    public static func resolve1<T:SequenceType where T.Generator.Element:MatchNormElement>(list: T, lti: LinearTransformation, accuracy: Double) -> LinearTransformation {
        // no problem
        return MatchNorm.resolve1(list, lti: lti, accuracy: accuracy)
    }

    public static func resolve2<T:SequenceType where T.Generator.Element:MatchNormElement>(list: T, lti: LinearTransformation, accuracy: Double) -> LinearTransformation {

        for elem in list {
            print(elem.x)
        }
        return lti
    }
}
public class MatchNormTest: XCTestCase  {
    func testMatchNorm1() {
        var list = [MatchNormElement]()

        // compilation error here!
        let  ll = MatchNorm.resolve1(list, lti: LinearTransformation(1), accuracy: 0.001)
// MatchNormTest.swift:70:29: Cannot invoke 'resolve1' with an argument list of type '([MatchNormElement], lti: LinearTransformation, accuracy: Double)'
// MatchNormTest.swift:70:29: Expected an argument list of type '(T, lti: LinearTransformation, accuracy: Double)'
    }
}

更新

MatchNormElement 是一个协议,所以我把它改成了具体类型。现在可以了。

func testMatchNorm1() {
    var list = [Measurment]()

        // works fine
     let  ll = MatchNorm.resolve1(list, lti: LinearTransformation(1), accuracy: 0.001)
}

这对编译器来说是合理的。 Swift 允许将具体类型转换为基于协议的变量赋值。

但是,Swift 不允许通过相互转换将一组具体类型转换为 set/array 协议。这是合理的,原因如下:

假设我们有这样的构造:

protocol IntType {}
extension Int: IntType{}

现在让我们做一件显而易见的事情:

let item = 12
let item2:IntType = item

然后是一个看起来很明显的:这有充分的理由无法编译。

let a = [1,2,3]
let b: [IntType] = a

让我们在继续之前检查每种类型的大小:

sizeofValue(item)   //8
sizeofValue(item2)  //40

数组是 8 字节的传染性内存。 Array 也是一个 40 字节的传染性内存。

我们这样做的时候:

let b: [IntType] = a

我们基本上告诉编译器将 8 字节的数组转换为 40 字节的数组并存储它。现在由于数组具有传染性,它必须销毁或重新洗牌,这是昂贵的这样做的任务。这阻碍了性能,显然你失去了类型安全。

编译器可以进行这种转换,但是 Swift 团队有充分的理由决定,如果用户想要进行这种类型转换,则需要明确说明,原因有两个:性能类型安全