2014-12-02 14 views
36

Sto sbattendo la testa contro il muro con il seguente codice in Swift. Ho definito un semplice protocollo:Impossibile assegnare alla proprietà nel protocollo - Errore del compilatore Swift

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

ed implementato con:

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

e poi ho il seguente metodo in un altro file (non chiedetemi perché):

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

Il problema è che il compilatore fornisce il seguente errore per l'assegnazione della proprietà in questo metodo:

non può assegnare al 'nome' in 'nominabile'

non riesco a vedere quello che sto facendo male ... Il seguente codice compila bene:

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

Sono certo è qualcosa di semplice che ho trascurato - cosa sto sbagliando?

risposta

30

È perché, essendo un protocollo, Swift non sa cosa tipo (sapore) dell'oggetto che la funzione in ingresso è Nameable. Potrebbe essere un'istanza di classe, certo - ma potrebbe essere un'istanza di struct. E si Non è possibile assegnare a una proprietà di una costante struct, come il seguente esempio illustra:

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

Beh, per impostazione predefinita, un parametro di funzione in entrata è una costante - è esattamente come se si aveva detto let nella dichiarazione di funzione prima che tu dicessi nameable.

La soluzione è quello di rendere questo parametro non essere una costante:

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

tl; dr cambiamento "lasciare myProtocolConformingItem" a "var myProtocolConformingItem" –

+0

@ Matt Anche se questa proposta/soluzione sicuramente funziona ed è attualmente proposto dal compilatore, lo consideri un odore di codice? – damirstuhec

+0

sto ricevendo errore 'uso del tipo non dichiarato di nameable' – Jack

76

@ anwer di Matt è corretta.

Un'altra soluzione è dichiarare Nameable come class only protocol.

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

Penso che questa soluzione sia più adatta per questo caso. Perché nameNameable è inutile a meno che nameable sia un'istanza di class.

+0

Il mio apprezzamento per Swift è cresciuto a causa di questo. –

+0

Questo +10000.Stavo avendo problemi importanti nell'implementare un protocollo ed estensioni che coinvolgevano una proprietà struct, e non ero in grado di mutarlo senza ogni sorta di mal di testa, ma l'aggiunta di 'class' risolveva tutto. – Mike

+0

Perché funziona, ma non "protocollo Nameable where Self: UIView' (supponendo che tu voglia solo ereditare questo protocollo). UIView è una classe, ma in realtà non eliminerà il suo errore. – GoldenJoe

0

qui, ho scritto un codice, che potrebbe dare qualche idea su Associated generico tipo di utilizzo:

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 
Problemi correlati