首页 > 解决方案 > 在非类绑定协议的扩展中,实例必须被视为值类型

问题描述

这是代码:

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
}

我有点理解这里的问题,但我真的很想得到更深入理解的人的回答,更重要的是我的问题的解决方法,即我想传递已知的类类型并能够使用方便的访问器不受我无法使用值类型的限制。就我而言,定义这些方便访问器的协议不应该是类绑定的(它们对值类型完全有效且有用),因此虽然这在技术上是一种解决方法,但我并不满意。

标签: swiftprotocolsimmutabilityvalue-typeprotocol-extension

解决方案


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

问题是,当convenientAccessor使用该属性时,编译器将instance其视为协议A,并且由于函数的参数是let's,它不允许对它们进行突变,因为此时协议也可以由值类型实现。

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

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

    protocol A: class 
    

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

  2. 制作函数参数inout

    func acceptsB (instance: inout B)
    

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

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


推荐阅读