通用工厂方法和类型推断

时间:2016-03-17 13:11:43

标签: swift generics

我有以下类使用通用工厂方法:

final class Something<T> {

    let value: T

    init(initial: T) {
        value = initial
    }

}

extension Something {

    class func zip<A, B>(a: A, _ b: B) -> Something<(A, B)> {
        let initial = (a, b)
        return Something<(A, B)>(initial: initial)
    }

}

为什么我不能在没有明确指定返回类型的情况下调用zip

// ERROR: Cannot invoke `zip` with an argument list of type `(Int, Int)`
let y = Something.zip(1, 2)

// OK: Works but it’s unacceptable to require this on caller's side
let x = Something<(Int, Int)>.zip(1, 2)

感谢您的时间!

3 个答案:

答案 0 :(得分:2)

你看到这个的原因是这次电话没有任何内容:

let y = Something.zip(1, 2)

告诉Swift T应该是什么。

您的调用隐式指定AB应该是什么,并指定方法应返回Something<A, B>。但Something<A, B>未与Something<T>相关联。

事实上,您的通话中没有任何内容与T相关联; T未指定,因此它可以是任何内容。我的意思是字面意思 - 你实际上可以在Something之后将(几乎)任意随机类型放在尖括号中并且它将完全相同:

let y = Something<UICollectionViewDelegateFlowLayout>.zip(1, 2)

你真正想做的是以某种方式指定T必须是元组,并且这两个参数与元组元素的类型相同。不幸的是,Swift目前还没有正确执行此操作所需的功能。如果语言更复杂,你可以这样说:

extension<A, B> Something where T == (A, B) {
    class func zip(a: A, _ b: B) -> Something {
        let initial = (a, b)
        return Something(initial: initial)
    }
}

但是现在,你将不得不处理这个可怕的黑客攻击,它通过毫无意义地重用T类型参数来使其不再处于松散状态:

extension Something {
    class func zip<B>(a: T, _ b: B) -> Something<(T, B)> {
        let initial = (a, b)
        return Something<(T, B)>(initial: initial)
    }
}

答案 1 :(得分:1)

简而言之,您使用泛型不正确。它不是实时功能,它是预编译的东西。如果您需要从通用输入值中创建抽象类,请查看并执行以下操作:

class Abstract<T> {
    init(value: T) {
        print("inputed value: \(value)")
    }
}

class Something {
    class func zip<A, B>(value: A, value2: B) -> Abstract<(A, B)> {
        print("Something.zip", value, value2)

        return Abstract<(A, B)>(value: (value, value2))
    }
}

Something.zip(5, value2: 40) // "inputed value: (5, 40)"

答案 2 :(得分:0)

T以这种方式与AB无关,因此无法推断。

例如

let z = Something<(String, String)>.zip(1, 2)
let z2 = Something<AnyObject>.zip(1, 2)

可以正常工作以返回Something<(Int, Int)>