swift - 在非类绑定(bind)协议(protocol)的扩展中,实例必须被视为值类型

标签 swift protocols immutability value-type protocol-extension

代码如下:

protocol A {
  var a: Int { get set }
}

extension A {
  var convenientAccessor: Int {
    get { return a }
    set { a = newValue }
  }
}

class B: A {
  var a: Int = 0
}

func acceptsB (instance: B) {
  instance.a = 1                     // This compiles
  instance.convenientAccessor = 2    // This does not
}

我有点理解这里的问题,但我真的很想得到更深入理解它的人的回答,更重要的是我的问题的解决方法,即我想传递已知的类类型并能够使用方便的访问器,而不会被我使用值类型的可能性所抑制。在我的例子中,定义这些方便的访问器的协议(protocol)不应该是类绑定(bind)的(它们对于值类型是完全有效和有用的),所以虽然这在技术上是一种解决方法,但我并不满意。

最佳答案

让我们从一个总结开始:convenientAccessor 是一个可写属性,因此对它的任何赋值都会导致突变。这种突变发生在您的函数内部。

问题在于,当使用 convenientAccessor 属性时,编译器将 instance 视为协议(protocol) A,并且因为函数的参数是 let,它不允许对它们进行修改,因为此时协议(protocol)也可以通过值类型实现。

我想到的两个解决方案是:

  1. 将协议(protocol) A 限制为仅类:

    protocol A: class 
    

    这会通知编译器只有类才能符合协议(protocol),这允许对任何类型的变量(letvar)进行修改

    <
  2. 使函数参数inout:

    func acceptsB (instance: inout B)
    

    这会创建一个“写入漏洞”,因为现在 instance 是可写的,所以对它的任何更改都会传播回上游,即使 B 是一个值类型。

就个人而言,如果您计划只使用类,我会选择 #1,正如您在问题中提到的那样。

关于swift - 在非类绑定(bind)协议(protocol)的扩展中,实例必须被视为值类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52417947/

相关文章:

memory - erlang中的数组实现

scala - 关于Scala变量可变性的问题

ios - 向 UIWindow 添加一个按钮。最佳实践?

ios - ScrollView : unexpectedly found nil while unwrapping an Optional value

ios - swift 的字符串类型是否符合集合协议(protocol)?

design-patterns - 快速程序接口(interface)

ios - SecurityApplicationGroupIdentifier 的应用组返回 nil

ios - 获取花名册而不是组列表 XMPP iOS Swift

java - 我遇到了 HTTP 和 HTTPS 协议(protocol)问题

java - 谷歌 Collection ( Guava 图书馆): ImmutableSet/List/Map and Filtering