繁体   English   中英

通用工厂方法和类型推断

[英]Generic factory method and type inference

我有以下带有通用工厂方法的 class:

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)

感谢您的时间!

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

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)
    }
}

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

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)"

T就这样简单地与AB无关,因此无法推断。

例如。

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

工作得很好,可以返回Something<(Int, Int)>

您可以像这样为您的案例引入类型推断:

final class Something<T> {

    let value: T

    init(initial: T) {
        value = initial
    }

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

}

let y = Something.zip(1, 2) //works

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM