2016-04-24 14 views
6

Tôi có một giao thức mã cơ sở nhanh chóng của tôi Tôi có giao thức với một loại liên kết và hai phương pháp. Cả hai phương thức xác định các ràng buộc chung khác nhau cho kiểu liên kết của giao thức. Và tôi muốn làm cho cấu trúc phù hợp với hai giao thức nhưng với hai loại liên quan khác nhau.thực hiện giao thức với loại liên quan khác nhau

protocol Convertable { 
    associatedtype TargetType 
    func convert() -> TargetType 
} 

func show<T : Convertable where T.TargetType == String>(toShow : T) { 
    print(toShow.convert()) 
} 
func add<T : Convertable where T.TargetType == Int>(a : T, b : T) -> Int { 
    return a.convert() + b.convert() 
} 

struct MyData { 
    var data : Int 
} 

Như một phần mở rộng tôi làm cho struct phù hợp với giao thức nơi TargetType sẽ String để vượt qua nó với phương pháp hiển thị:

extension MyData : Convertable { 
    func convert() -> String { return String(self.data) } 
} 

Cho đến nay mọi thứ hoạt động như mong đợi. Nhưng bây giờ tôi cũng muốn có cấu trúc để phù hợp với giao thức Convertable khi TargetType bị ràng buộc với một Int. Điều đó dường như là không thể?

Điều đầu tiên tôi đã cố gắng là để thêm một định nghĩa thứ hai của phương pháp chuyển đổi sang phần mở rộng:

extension MyData : Convertable { 
    func convert() -> String { return String(self.data) } 
    func convert() -> Int { return data } 
} 

Trình biên dịch tại phàn nàn rằng MyData nào không còn phù hợp với các giao thức. Thứ hai là chia thành hai phần mở rộng và ràng buộc TargetType một cách rõ ràng.

extension MyData : Convertable { 
    typealias TargetType = Int 
    func convert() -> Int { return data } 
} 
extension MyData : Convertable { 
    typealias TargetType = String 
    func convert() -> String { return String(data) } 
} 

Điều này có hiệu lực mà trình biên dịch hiện đã khiếu nại TargetType được xác định lại.

thử cuối cùng của tôi là để xác định hai giao thức mở rộng giao thức Convertable và hạn chế TargetType và sau đó thực hiện cả trong số họ thông qua phần mở rộng:

protocol ConvertableString : Convertable { 
    associatedtype TargetType = String 
} 
protocol ConvertableInt : Convertable { 
    associatedtype TargetType = Int 
} 

extension MyData : ConvertableInt { 
    func convert() -> Int { return self.data } 
} 
extension MyData : ConvertableString { 
    func convert() -> String { return String(self.data) } 
} 

Mà bây giờ làm cho trình biên dịch hạnh phúc cho các phần mở rộng nhưng không còn cho cuộc gọi đến show bởi vì nó không biết rằng nó có thể gọi chức năng với MyData.

Có một số điều mà tôi đã giám sát hoặc hiện tại điều này không thể nhanh chóng?

+1

Hiện tại, không chỉ hiện tại là không thể, nhưng hầu như không bao giờ có thể, theo ý kiến ​​của tôi. Bạn đã khai báo một giao thức với loại _one single_ được kết hợp. Làm thế nào nó có thể được thiết lập để hai loại khác nhau cùng loại ?! – werediver

+1

Vâng, nó không phải là cùng một giao thức, vì giao thức là chung trên TargetType có nhiều biến thể của giao thức như có cho TargetType. Toàn bộ ý tưởng về việc có các kiểu liên kết với các giao thức là bạn có thể phân biệt theo kiểu liên kết của chúng. Nếu bạn nhìn vào C#, có thể thực hiện cùng một giao diện với các kiểu khác nhau được ràng buộc với tham số chung. – Kolja

+0

Vâng, nó không phải là C# và bạn không nên nghĩ về nó vì nó sẽ được, bởi vì điều đó chỉ không hoạt động. – werediver

Trả lời

1

Tôi chỉ tài trợ một cách để lưu trữ điều này. Bí quyết là thêm loại được liên kết khác vào một trong các loại phụ của giao thức:

protocol ConvertableInt : Convertable { 
    associatedtype TResI 
    typealias TargetType = TResI 
} 

extension MyData : Convertable { 
    typealias TargetType = String 
    func convert() -> String { return String(self.data) } 
} 

extension MyData : ConvertableInt { 
    typealias TResI = Int 
    func convert() -> TResI { return self.data } 
} 

Điều này cũng cho phép loại bỏ loại phụ thứ hai cho chuỗi.

Trong khi điều này vượt qua trình biên dịch, nó hoàn toàn bị treo khi chạy!

Trình biên dịch luôn gọi phương thức được xác định đã được xác định tại typealias rõ ràng. Trong trường hợp này:

typealias TargetType = String 

Điều này sẽ dẫn đến việc giải thích địa chỉ dưới dạng số nguyên và cho bạn kết quả hoàn toàn sai. Nếu bạn xác định nó ngược lại nó sẽ chỉ đơn giản là sụp đổ vì nó cố gắng giải thích số nguyên như là một địa chỉ.

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