无法在协议中分配属性 - Swift编译器错误

ole*_*mar 47 ios swift

我在Swift中使用以下代码将我的头撞在墙上.我已经定义了一个简单的协议:

protocol Nameable {
    var name : String { get set }
}
Run Code Online (Sandbox Code Playgroud)

并通过以下方式实施:

class NameableImpl : Nameable {
    var name : String = ""
}
Run Code Online (Sandbox Code Playgroud)

然后我在另一个文件中有以下方法(不要问我为什么):

func nameNameable( nameable: Nameable, name: String ) {
    nameable.name = name
}
Run Code Online (Sandbox Code Playgroud)

问题是编译器在此方法中为属性赋值提供以下错误:

无法在"名字"中指定"名称"

我看不出我做错了什么......以下代码编译得很好:

var nameable : Nameable = NameableImpl()
nameable.name = "John"
Run Code Online (Sandbox Code Playgroud)

我确信这是我忽略的一些简单 - 我做错了什么?

rin*_*aro 97

@ matt的anwer是正确的.

另一种解决方案是声明Nameableclass唯一的协议.

protocol Nameable: class {
//               ^^^^^^^ 
    var name : String { get set }
}
Run Code Online (Sandbox Code Playgroud)

我认为,这种解决方案更适合这种情况.因为nameNameable除非nameable是实例,否则无用class.

  • 我对 Swift 的欣赏也因此变得更加强烈。 (2认同)

mat*_*att 38

这是因为,Nameable是一个协议,Swift不知道你的函数的Nameable是什么类型(风味).它可能是一个类实例,当然 - 但它可能是一个struct实例.并且您无法分配常量结构的属性,如以下示例所示:

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

好吧,默认情况下,传入的函数参数一个常量 - 就像你let在你说的之前在函数声明中所说的那样nameable.

解决方案是使此参数不是常量:

func nameNameable(var nameable: Nameable, name: String ) {
                  ^^^
Run Code Online (Sandbox Code Playgroud)

注意后来的Swift版本已经废除了var函数参数表示法,因此您可以通过将常量赋值给变量来完成相同的操作:

protocol Nameable {
    var name : String { get set }
}
func nameNameable(nameable: Nameable, name: String) {
    var nameable = nameable // can't compile without this line
    nameable.name = name
}
Run Code Online (Sandbox Code Playgroud)

  • @Jack那是几年前的事了!我的答案现在不是有效的 Swift 语法 (2认同)