我为什么要投力的属性到一个通用的方法具有相同签名的财产?

时间:2019-01-31 20:12:34

标签: swift generics

这是我的代码:

class GenericClass<T: UITableViewCell> {

    let enumProperty = SomeEnum.myValue

    enum SomeEnum {
        case myValue
    }

    func callOtherClass() {
        OtherClass.handle(property: enumProperty) // Compile error
    }
}

class OtherClass {
    static func handle(property: GenericClass<UITableViewCell>.SomeEnum) {}
}

为什么会出现编译错误:

  

无法将类型“ GenericClass.SomeEnum”的值转换为预期值   参数类型'GenericClass.SomeEnum'

Ofcourse,修复将被加入铸:

as! GenericClass<UITableViewCell>.SomeEnum

,其结果在该丑陋的代码:

func callOtherClass() {
    OtherClass.handle(property: enumProperty) as! GenericClass<UITableViewCell>.SomeEnum
}

但是为什么我需要投射? self被定义为GenericClass,其中T始终是UITableViewCell。该方法handle期望的签名。

在某些情况下是否需要这种施法,因为在某些情况下这样做会/可能失败?我不希望Swift会随机要求我插入强制施法。我希望斯威夫特可以只推断出类型,并认为它是安全的,但不知何故,斯威夫特不同意我的观点。

2 个答案:

答案 0 :(得分:2)

使您的静态方法也通用,并为从UITableViewCell继承的参数创建通用约束。然后在方法参数中使用该通用参数

class OtherClass {
    static func handle<T: UITableViewCell>(property: GenericClass<T>.SomeEnum) {}
}

答案 1 :(得分:2)

这里的问题是SomeEnum实际上是GenericClass<T>.SomeEnum。无法保证T就是UITableViewCell,因此它与GenericClass<UITableViewCell>generics are not covariant)不兼容。

通常,在这种情况下,您想要做的是将SomeEnum移到GenericClass之外,因为实际上没有什么是通用的:

enum SomeEnum {
    case myValue
}

class GenericClass<T: UITableViewCell> {

    let enumProperty = SomeEnum.myValue

    func callOtherClass() {
        OtherClass.handle(property: enumProperty) // Compile error
    }
}

class OtherClass {
    static func handle(property: SomeEnum) {}
}

但是如果有一个通用的原因,请参见Robert Dresler的答案,这就是您正确地对该功能进行专业化处理的方式:

class OtherClass {
    static func handle<T: UITableViewCell>(property: GenericClass<T>.SomeEnum) {}
}