swift - Swift 中的类绑定协议细化
问题描述
为什么这段代码会引发编译错误?
protocol P { var i: Int { get set } }
protocol ClassP: P, AnyObject {}
class C: ClassP { var i: Int = 0 }
let classP: ClassP = C()
classP.i = 1 // Cannot assign to property: 'classP' is a 'let' constant
但是,如果我将AnyObject
限制移至P
:
protocol P: AnyObject { var i: Int { get set } }
protocol ClassP: P {}
class C: ClassP { var i: Int = 0 }
let classP: ClassP = C()
classP.i = 1
请注意在两个示例classP
中的类型为ClassP
, 并且ClassP
是类绑定的。但是编译器似乎注意到,只有当属性在本身已经是类绑定的协议中声明时,赋值才会针对类实例的属性(而不是结构实例)。的静态类型classP
似乎被忽略了。为什么?
理想情况下P
,它本身不应该是类绑定的,因为它很容易具有非类绑定的细化和符合类型。当然,在这些情况下,p.i = 1
分配仅对 writeable 有效p
。使用 let-const p
,p.i = 1
仅当p
已知是符合类的实例时才有效(我认为在上面的示例中是正确的,因为已知类型是ClassP
并且确实是类绑定的)。我如何在 Swift 中表达这一点?
解决方案
不漂亮,但添加i
作为ClassP
沉默错误的要求:
protocol P { var i: Int { get set } }
protocol ClassP: P, AnyObject { var i: Int { get set } }
class C: ClassP { var i: Int = 0 }
let classP: ClassP = C()
classP.i = 1
推荐阅读
- python - 如果 BaseModel 得到意外参数,如何让 pydantic 引发 ValidationError
- python - 有没有办法从 get_queryset 返回两个组合列表,而不仅仅是查询集?
- javascript - 加载 mat-tab 时会触发 selectTabChange 事件,因为当我们在加载后选择任何选项卡时应该触发它。角材料选项卡
- kubernetes - 阻止 k8s 作业的执行,直到在 helm 图表中完成另一个作业
- html - 仅使用 html 设置 div 背景颜色
- typescript - ESLint 不相信我在我的 tsconfig 中包含了 .vue 文件
- javascript - overflow-y 的滚动条从底部开始
- javascript - ./node_modules/rc-align/es/Align.js 中的错误
- javascript - Angular - 表格排序不适用于嵌套对象
- google-chrome-extension - 如何知道我的 chrome 扩展需要哪些权限?