2014-12-02 21 views
36

Tôi đang đập đầu vào tường bằng đoạn mã sau trong Swift. Tôi đã xác định một giao thức đơn giản:Không thể gán cho thuộc tính trong giao thức - Lỗi biên dịch Swift

protocol Nameable { 
    var name : String { get set } 
} 

và thực hiện điều đó với:

class NameableImpl : Nameable { 
    var name : String = "" 
} 

và sau đó tôi có các phương pháp sau đây trong tập tin khác (đừng hỏi tôi tại sao):

func nameNameable(nameable: Nameable, name: String) { 
    nameable.name = name 
} 

Vấn đề là trình biên dịch cung cấp lỗi sau cho việc gán thuộc tính trong phương thức này:

không thể gán cho 'tên' trong 'nameable'

Tôi không thể nhìn thấy những gì tôi đang làm sai ... Các mã sau biên dịch tốt:

var nameable : Nameable = NameableImpl() 
nameable.name = "John" 

Tôi chắc chắn nó là một cái gì đó đơn giản tôi đã bỏ qua - tôi đang làm gì sai?

Trả lời

30

Đó là vì, Nameable là một giao thức, Swift không biết những gì loại (hương vị) của đối tượng chức năng có thể đặt tên của bạn là. Nó có thể là một cá thể lớp, chắc chắn - nhưng nó có thể là một cá thể struct. Và bạn không thể gán cho một tài sản của một cấu trúc liên tục, như ví dụ dưới đây trình bày:

struct NameableStruct : Nameable { 
    var name : String = "" 
} 
let ns = NameableStruct(name:"one") 
ns.name = "two" // can't assign 

Vâng, theo mặc định, một tham số chức năng đến một hằng số - đó là chính xác như nếu bạn đã nói let trong khai báo hàm của bạn trước khi bạn nói nameable.

Giải pháp là làm cho thông số này không là một hằng số:

func nameNameable(var nameable: Nameable, name: String) { 
        ^^^ 
+0

tl; dr thay đổi "để myProtocolConformingItem" thành "var myProtocolConformingItem" –

+0

@ Matt Trong khi đề xuất này/giải pháp chắc chắn công trình và hiện tại thậm chí được đề xuất bởi trình biên dịch, bạn có cho rằng đó là một mã nguồn không? – damirstuhec

+0

tôi đang gặp lỗi 'sử dụng loại không khai báo có thể đặt tên' – Jack

76

@ anwer mờ là đúng.

Một giải pháp khác là khai báo Nameable dưới dạng class only protocol.

protocol Nameable: class { 
//    ^^^^^^^ 
    var name : String { get set } 
} 

Tôi nghĩ, giải pháp này phù hợp hơn cho trường hợp này. Vì nameNameable là vô dụng trừ khi nameable là một phiên bản của class.

+0

Sự đánh giá cao của tôi đối với Swift chỉ lớn hơn vì điều này. –

+0

+10000 này.Tôi đã gặp phải các vấn đề lớn khi triển khai một giao thức và các phần mở rộng liên quan đến một thuộc tính struct, và không thể thay đổi nó mà không có tất cả các loại nhức đầu, nhưng việc thêm 'class' đã giải quyết mọi thứ. – Mike

+0

Tại sao điều này làm việc, nhưng không phải là 'giao thức Nameable nơi Tự: UIView' (giả sử bạn chỉ muốn xem để kế thừa giao thức này). UIView là một lớp học, nhưng nó sẽ không thực sự thoát khỏi lỗi của mình. – GoldenJoe

0

Ở đây, tôi viết một số mã, mà có thể đưa ra một số ý tưởng về Associated generic loại Cách sử dụng:

protocol NumaricType 
{ 
    typealias elementType 
    func plus(lhs : elementType, _ rhs : elementType) -> elementType 
    func minus(lhs : elementType, _ rhs : elementType) -> elementType 
} 

struct Arthamatic :NumaricType { 

func addMethod(element1 :Int, element2 :Int) -> Int { 
    return plus(element1, element2) 
} 
func minusMethod(ele1 :Int, ele2 :Int) -> Int { 
    return minus(ele1, ele2) 
} 
typealias elementType = Int 

func plus(lhs: elementType, _ rhs: elementType) -> elementType { 
    return lhs + rhs 
} 
func minus(lhs: elementType, _ rhs: elementType) -> elementType { 
    return lhs - rhs 
} 
} 
**Output:** 
let obj = Arthamatic().addMethod(34, element2: 45) // 79 
Các vấn đề liên quan