【问题标题】:Swift: Generics and type constraints, strange behaviorSwift:泛型和类型约束,奇怪的行为
【发布时间】:2018-12-15 03:27:14
【问题描述】:

我不知道如何进行强制转换,最终让我引入某种与泛型一起工作的活力。

下一段代码无法编译。它显示了这个错误:

无法使用类型参数列表调用“createContainer” '(FooProtocol)' 需要一个类型为 '(T)' 的参数列表

protocol FooProtocol {
    func doSomething()
}

class Foo : FooProtocol {
    func doSomething() {}
}

class Container<T : FooProtocol> {
    let someDataConformingFooProtocol : T

    init(someDataConformingFooProtocol : T) {
        self.someDataConformingFooProtocol = someDataConformingFooProtocol
    }
}

class AllTogether {

    init () {
        createContainer(Foo()) //So far, so good

        let foo2Mask : AnyObject = Foo()
        if let foo2MaskChecked = foo2Mask as? FooProtocol {
            createContainer(foo2MaskChecked)
            //ERROR: Cannot invoke 'createContainer' with an argument list of type '(FooProtocol)'
            //Expected an argument list of type '(T)'
        }

    }

    func createContainer<T : FooProtocol>(data: T){
        Container<T>(someDataConformingFooProtocol: data)
    }
}

这真的是预期的行为吗?因为我个人无法理解编译器在抱怨什么或为什么抱怨它。

合适的演员阵容是什么?如果不引用具体类,我的意思是不是这样的:

if let foo2MaskChecked = foo2Mask as? Foo 

谢谢!

【问题讨论】:

  • 这与类型差异有关。阅读以下内容:nomothetis.svbtle.com/type-variance-in-swift
  • 我明白了。帖子的最后一个例子说明了同样的问题。似乎目前没有解决方案。谢谢!
  • @MikePollard 你能解释一下方差是如何在这里起作用的吗?我们不会试图将Container&lt;T&gt; 冒充为Container&lt;FooProtocol&gt;;我们所尝试的只是将一些U: FooProtocol 传递给带有签名T: FooProtocol 的方法。直觉上,UT 统一了,所以一切都应该很好。我错过了什么?
  • 有些日子,我想念 Scala。
  • FWIW,我认为类协议在这里应该有所帮助,但没有。 See this follow-up question.

标签: swift


【解决方案1】:

归结为@Hamish 在他的评论中提到的T: FooProtocolFooProtocol 之间的区别。

当我有这样的功能时:

func foo(_ i: FooProtocol)

我正在接收FooProtocol 类型的实例,因此我可以传入一个符合FooProtocol 或其类型为FooProtocol 的值。这类似于子类化,您可以将SuperClassSubClass 都传递给SuperClass

但如果你有这样的功能:

func foo<T>(_ i: T) where T: FooProtocol

我可以传入任何符合FooProtocol 的类型,但是因为FootProtocol 不符合自己,所以不能传入。

因此,在您的问题中,您尝试传入一个类型 FooProtocol,其中类型必须符合FooProtocol。您可以通过以下方式解决此问题:

class Container {
    let someDataConformingFooProtocol: FooProtocol

    init(someDataConformingFooProtocol: FooProtocol) {
        self.someDataConformingFooProtocol = someDataConformingFooProtocol
    }
}

// Later
func createContainer(data: FooProtocol){
    Container(someDataConformingFooProtocol: data)
}

【讨论】:

    猜你喜欢
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多