【问题标题】:Can't create an Array of types conforming to a Protocol in Swift无法在 Swift 中创建符合协议的类型数组
【发布时间】:2014-11-11 13:13:39
【问题描述】:

我有以下协议和一个符合它的类:

protocol Foo{
    typealias BazType

    func bar(x:BazType) ->BazType
}


class Thing: Foo {
    func bar(x: Int) -> Int {
        return x.successor()
    }
}

当我尝试创建一个 foos 数组时,我收到一个奇怪的错误:

var foos: Array<Foo> = [Thing()]

Protocol Foo 只能用作通用约束,因为它具有 自身或关联的类型要求。

好的,所以它只能在它有关联的类型要求时使用(它确实如此),但由于某种原因这是一个错误? WTF?!

我不确定我是否完全理解编译器试图告诉我的内容...

【问题讨论】:

标签: swift protocols associated-types


【解决方案1】:

假设我们可以将Thing 的实例放入数组foos 中,会发生什么?

protocol Foo {
    typealias BazType

    func bar(x:BazType) -> BazType
}

class Thing: Foo {
    func bar(x: Int) -> Int {
        return x.successor()
    }
}

class AnotherThing: Foo {
    func bar(x: String) -> String {
        return x
    }
}

var foos: [Foo] = [Thing()]

因为AnotherThing也符合Foo,所以我们也可以把它放到foos中。

foos.append(AnotherThing())

现在我们从foos 中随机获取一个foo

let foo = foos[Int(arc4random_uniform(UInt32(foos.count - 1)))]

我要调用方法bar,你能告诉我应该向bar发送一个字符串还是一个整数?

foo.bar("foo")foo.bar(1)

斯威夫特不能。

所以它只能作为一个通用的约束。

什么场景需要这样的协议?

示例:

class MyClass<T: Foo> {
        let fooThing: T?

        init(fooThing: T? = nil) {
                self.fooThing = fooThing
        }

        func myMethod() {
                let thing = fooThing as? Thing // ok
                thing?.bar(1) // fine

                let anotherThing = fooThing as? AnotherThing // no problem
                anotherThing?.bar("foo") // you can do it

                // but you can't downcast it to types which doesn't conform to Foo
                let string = fooThing as? String // this is an error
        }
}

【讨论】:

    【解决方案2】:

    我一直在研究您的代码,试图了解如何实现该协议。我发现您不能将 Typealias 用作泛型类型,因为它只是别名而不是类型本身。因此,如果您在协议和类之外声明 Typealias,您可以在代码中有效地使用它而不会出现任何问题。

    注意: Typealias 在其声明中包含 Int 类型,这样您就可以始终使用别名而不是 Int 类型,并使用其所有关联的方法和函数。

    我是这样工作的:

    typealias BazType = Int
    
    protocol Foo{
      func bar(x:BazType) -> BazType
    }
    
    class Thing: Foo {
      func bar(x: BazType) -> BazType {
        return x.successor()
      }
    }
    
    let elements: Array<Foo> = [Thing(), Thing()]
    

    【讨论】:

    • 在这段代码中 BazType 只是 Int 而不是变量类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多