2014-12-02 7 views
36

Я стучу головой о стену со следующим кодом в Swift. Я определил простой протокол:Невозможно назначить свойство в протоколе - ошибка компилятора Swift

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

и Реализована с:

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

, а затем я следующий метод в другом файле (не спрашивайте меня, почему):

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

Проблема заключается в том, что компилятор дает следующую ошибку для присвоения свойства в этом методе:

не может присвоить имя «» в «» именуема

Я не могу увидеть, что я делаю неправильно ... Следующий код компилируется нормально:

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

Я уверен, что это что-то простое, я забыл - что я делаю неправильно?

ответ

30

Это потому, что имя, являющееся протоколом, Swift не знает, что вид (аромат) объекта, входящего в вашу функцию. Это может быть экземпляр класса, конечно - но это может быть экземпляр структуры. И вы не можете присвоить свойству постоянной структуры, как показано в следующем примере показано:

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

Ну, по умолчанию, входящий параметр функции является константа - это точно так, как если вы сказал let в объявлении вашей функции, прежде чем вы сказали nameable.

Решение сделать этот параметр не быть постоянным:

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

Т.Л., изменение др «пусть myProtocolConformingItem» в «вар myProtocolConformingItem» –

+0

@ Matt Хотя это предложение/решение, безусловно, работает и в настоящее время даже предлагается компилятором, считаете ли вы его запахом кода? – damirstuhec

+0

Я получаю ошибку 'использование необъявленного типа именного' – Jack

76

@ Anwer Мэтта правильно.

Другим решением является объявление Nameable как class only protocol.

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

Я думаю, этот вариант более подходит для этого случая. Потому что nameNameable бесполезен, если nameable не является экземпляром class.

+0

Моя благодарность за Swift просто выросла из-за этого. –

+0

Этот +10000.У меня возникли серьезные проблемы с внедрением протокола и расширений, в которых было свойство struct, и он не мог мутировать его без всяких головных болей, но добавление 'class' решало все. – Mike

+0

Почему это работает, но не 'protocol Nameable where Self: UIView' (предполагая, что вы просто хотели, чтобы представления наследовали этот протокол). UIView - это класс, но он фактически не избавится от его ошибки. – GoldenJoe

0

Здесь я написал код, который может дать некоторое представление об ассоциированном универсального типа использования:

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 
Смежные вопросы