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

Swift中如何让结构体实例共享同一属性且避免拷贝?

问题场景与代码示例

我会实例化大量B类型的值,且A的实例值永远不会改变,B的很多函数都需要依赖这个A实例才能运行。现有两种实现方式,但都存在缺陷:

Case 1: 将A作为结构体属性

struct A {}

struct B {
  let a: A
  // 大量依赖a的函数
  func foo1() -> B {...}
  func foo2() -> B {...}
  ...
}

let a = A()
let b = B(a: a)
b.foo1()

缺陷:每次创建新B实例都会拷贝a,当A体积较大时会带来不必要的性能开销。

Case 2: 每次调用函数传入A

struct A {}

struct B {
  func foo1(a: A) -> B {...}
  func foo2(a: A) -> B {...}
  ...
}

let a = A()
let b = B()
b.foo1(a: a)

缺陷:无需拷贝a,但每次调用函数都要手动传入,开发体验差。

我希望能存储a但不拷贝它,就像C语言中使用引用那样,请问有什么解决方案?

解决方案

1. 用类包装A(最常用、推荐)

利用Swift中类的引用语义,要么直接把A改为类,要么用类包装结构体A的实例,这样B存储的是类实例的引用,不会拷贝A的内容:

// 方案1:直接将A改为类
class A {}

struct B {
  let a: A
  func foo1() -> B {...}
  func foo2() -> B {...}
}

let a = A()
let b = B(a: a)
b.foo1()

// 方案2:用类包装结构体A
struct A {}
class ABox {
  let value: A
  init(_ value: A) {
    self.value = value
  }
}

struct B {
  let aBox: ABox
  func foo1() -> B {
    // 通过aBox.value访问A实例
    ...
  }
}

let a = A()
let aBox = ABox(a)
let b = B(aBox: aBox)

无论创建多少B实例,都会共享同一个类实例的引用,不会产生A的拷贝。

2. 使用不安全指针(仅性能极度敏感场景)

如果不想修改A的类型,可使用UnsafePointer存储A的内存地址,但需要手动保证A实例的生命周期长于所有B实例,否则会出现野指针问题,日常开发不推荐:

struct A {}

struct B {
  let aPtr: UnsafePointer<A>
  func foo1() -> B {
    let a = aPtr.pointee
    ...
  }
}

let a = A()
let b = B(aPtr: &a)
// 必须确保a的生命周期覆盖所有使用b的代码

3. 自定义引用语义包装结构体(兼顾语法与安全性)

用内部类存储A实例,对外暴露结构体接口,既保留值类型的使用习惯,又实现引用语义的共享:

struct A {}

struct SharedA {
  private final class Storage {
    let value: A
    init(_ value: A) {
      self.value = value
    }
  }
  private let storage: Storage
  init(_ value: A) {
    self.storage = Storage(value)
  }
  var value: A { storage.value }
}

struct B {
  let sharedA: SharedA
  func foo1() -> B {
    let a = sharedA.value
    ...
  }
}

let a = A()
let sharedA = SharedA(a)
let b = B(sharedA: sharedA)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:45:46