2014-11-11 16 views
15

Tôi có giao thức sau đây và một lớp học phù hợp với nó:Không thể tạo một mảng của các loại phù hợp với một Nghị định thư trong Swift

protocol Foo{ 
    typealias BazType 

    func bar(x:BazType) ->BazType 
} 


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

Khi tôi cố gắng tạo ra một mảng của foos, tôi nhận được một lỗi lẻ:

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

Protocol Foo can only be used as a generic constraint because it has Self or associated type requirements.

OK, vì vậy nó chỉ có thể được sử dụng nếu nó có một yêu cầu loại liên quan (mà nó), nhưng đối với một số lý do đây là một lỗi ?? WTF ?!

Tôi không chắc tôi hoàn toàn hiểu những gì các trình biên dịch đang cố gắng cho tôi biết ...

+0

thể trùng lặp của (http://stackoverflow.com/questions/26267597/cannot-assign-class-instance-to -its-protocol-type) – Antonio

Trả lời

13

Hãy nói rằng, nếu chúng ta có thể đặt một thể hiện của Thing vào mảng foos, điều gì sẽ xảy ra?

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 phù hợp với Foo quá, vì vậy chúng ta có thể đặt nó vào foos cũng có.

foos.append(AnotherThing()) 

Bây giờ, chúng tôi lấy một số foo từ foos ngẫu nhiên.

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

và tôi sẽ gọi phương thức bar, bạn có thể cho tôi biết rằng tôi nên gửi một chuỗi hoặc một số nguyên để bar?

foo.bar("foo") hoặc foo.bar(1)

Swift không thể.

Vì vậy, nó chỉ có thể được sử dụng như một ràng buộc chung.

Kịch bản nào yêu cầu một giao thức như thế này?

Ví dụ: [? Không thể gán dụ lớp để loại giao thức của nó]

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

Tôi đã được chơi với mã của bạn cố gắng tìm hiểu làm thế nào để thực hiện các giao thức. Tôi thấy rằng bạn không thể sử dụng Typealias như một loại chung chung bởi vì nó chỉ là một bí danh không phải là một loại của chính nó. Vì vậy, nếu bạn khai báo Typealias bên ngoài giao thức của bạn và lớp của bạn, bạn có thể sử dụng nó một cách hiệu quả trong mã của bạn mà không có bất kỳ vấn đề gì.

Lưu ý: Typealias có kiểu khai báo Int, theo cách đó bạn luôn có thể sử dụng bí danh thay vì kiểu Int và sử dụng tất cả các hàm và hàm liên quan của nó.

Đây là cách tôi làm cho nó hoạt:

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()] 
+0

trong mã này BazType chỉ là Int chứ không phải kiểu biến. –

Các vấn đề liên quan