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

为何用var声明的结构体传入函数后会变成let常量?

为什么用var声明的结构体实例传入函数后会被当作let常量?

这个问题刚好踩中了Swift里值类型和函数参数默认规则的核心,我来给你掰扯明白:

首先得明确两个关键知识点:

  • 结构体是值类型:值类型在传递(比如传给函数参数)的时候,会创建一个完整的副本,函数里拿到的是和原实例完全独立的新对象,不是同一个东西。
  • Swift函数参数默认是常量:不管你外部传入的是var还是let修饰的实例,函数内部接收到的参数默认都是let常量,不允许修改——这是语言的默认设计,目的是避免你不小心修改副本,同时保证函数的行为更可预测。

结合你的代码来看:

  • 外部的var s = S()是可变的,因为你直接持有这个实例的所有权,所以可以自由修改它的属性。
  • 但当你把s传给changeS(s:)时,函数会创建一个s的副本,而且这个副本默认是let常量,所以你在函数里尝试s.i *= 2时,就会报错“赋值运算符左侧不可变:'s'是一个'let'常量”——本质是你不能修改一个常量结构体的属性。

如果想要在函数里修改这个实例(不管是副本还是原实例),有两种常见解决办法:

1. 把参数声明为可变(仅修改副本)

如果只是想在函数内部修改副本,不影响外部原实例,可以给参数加上var修饰符:

struct S { var i: Int = 1 }
func changeS(var s: S) {
    s.i *= 2 // 现在合法了
    print(s.i) // 输出2
}
var s = S()
changeS(s: s)
print(s.i) // 输出1,原实例没被修改

2. 使用inout参数(修改原实例)

如果想要修改外部的原实例,需要用inout关键字标记参数,调用时还要在变量前加&符号:

struct S { var i: Int = 1 }
func changeS(s: inout S) {
    s.i *= 2 // 合法
}
var s = S()
changeS(s: &s)
print(s.i) // 输出2,原实例被修改

(注:inout对于值类型来说,本质是把实例拷贝进函数,修改后再拷贝回原变量,对外表现为直接修改原实例)

总结一下:你看到的现象,就是值类型的拷贝特性加上Swift函数参数默认是常量这两个规则共同作用的结果~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 03:17:43