You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中let声明的协议类型属性直接赋值报错调用set方法正常是什么原因

问题原因解析

这个问题的核心是Swift对协议类型属性赋值的突变性检查规则导致的:

第一种直接赋值报错的原因

  • 你定义的SubscriberContextProviding协议默认可以被类、结构体、枚举三种类型遵守。
  • 当你用let subscriber: SubscriberContextProviding声明常量时,编译器不知道subscriber背后的实际类型是引用类型(类)还是值类型(结构体/枚举):
    • 如果实际类型是值类型,修改它的{get set}属性本质是修改整个值实例本身,而let修饰的值类型常量是不允许修改的。
    • 编译器为了覆盖所有可能的遵守者场景,会直接禁止对let修饰的协议类型变量调用set属性,所以报Cannot assign to property: 'subscriber' is a 'let' constant错误。

第二种方法调用正常的原因

  • 协议中定义的普通方法(没有加mutating修饰),默认要求实现时不能修改值类型的实例本身:
    如果你用结构体/枚举遵守协议实现set(watchlist:)方法,不加mutating的话根本编译不通过,只有类实现的时候不需要mutating就能修改自身属性。
  • 你调用subscriber.set(watchlist: watchlist)时,编译器确认这个方法没有mutating修饰,不会修改值类型的实例本身,所以哪怕subscriber是let修饰的协议类型也允许调用。

扩展:让第一种写法也能正常运行的方案

如果你的协议本身就只打算给类遵守,可以直接给协议加上AnyObject约束:

protocol SubscriberContextProviding: AnyObject {
  var watchlist: [String] { get set }
}

加上这个约束后,编译器就知道所有遵守该协议的都是引用类型,let修饰只是限制不能修改subscriber的指针指向,完全允许修改指向对象的内部属性,这时候直接给subscriber.watchlist赋值就不会报错了。

内容的提问来源于stack exchange,提问作者lychee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:45:02