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

Swift计算属性出现重复值问题:为何得到[3,3,2]而非预期[3,2]?

为什么Swift计算属性调用append会导致重复值?

我来帮你拆解这个问题的核心原因——你误解了计算属性和值类型(比如Swift的Array)交互时的行为,尤其是调用mutating方法(比如append)时的隐式赋值逻辑。

一步一步还原你的代码执行流程

初始化阶段(init方法)

  1. 你先把_x初始化为空数组[]。
  2. 执行x?.append(3):
    • 首先调用计算属性x的getter,返回当前_x的值(空数组)。
    • 对这个返回的数组调用append(3),因为数组是值类型,这会创建一个新的数组实例[3]。
    • 关键来了:因为你是对计算属性的返回值进行修改,Swift会自动把这个修改后的新数组重新赋值给计算属性x,也就是触发了x的setter方法。
    • 在setter里,newValue就是刚才的[3],你遍历它的元素并追加到_x中(此时_x还是空数组),所以_x变成了[3]。

追加2的阶段

  1. 执行classTest.x?.append(2):
    • 调用x的getter,返回当前_x的值[3]。
    • 对这个数组调用append(2),再次创建新的数组实例[3,2]。
    • Swift再次自动把这个新数组赋值给x,触发setter。
    • 在setter里,newValue是[3,2],你把这两个元素都追加到现有的_x([3])里,最终_x就变成了[3,3,2]。

为什么和你的预期不符?

你以为调用x?.append(3)是直接修改_x,但实际上因为x是计算属性(而非存储属性),对它的返回值调用mutating方法会触发隐式赋值,进而触发你写的setter逻辑——而你的setter是把newValue的元素追加到_x,不是替换,这就导致了重复。

怎么修复?

如果你想让x的行为和普通的存储属性一样,直接操作_x,有两个选择:

  1. 把x改成存储属性,去掉getter和setter(或者干脆不用下划线命名,直接用x作为存储属性):
class Test {
    var x: [Int] = []
    init() {
        x.append(3)
    }
}
  1. 如果你必须保留计算属性,修改setter的逻辑为替换而非追加:
class Test {
    var _x : [Int]?
    var x : [Int]? {
        get { return _x }
        set { _x = newValue } // 直接替换,不是追加
    }
    init() {
        _x = [Int]()
        _x?.append(3) // 直接操作存储属性,避免不必要的getter/setter调用
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 15:57:40