μΌ | μ | ν | μ | λͺ© | κΈ | ν |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- νμ΄
- μ°μ°μ
- ꡬ쑰체
- async
- 리μ€νΈλ·°
- concurrency
- μ΅μ λ
- νλ‘κ·Έλλ¨Έμ€
- weak
- νλκ·Έλ¨ΌνΈ
- View
- noncopyable
- Subject
- ios
- RxSwift
- μ°¨μ΄
- μ΄μ€μΌμ΄ν
- μκ³ λ¦¬μ¦
- μλλ‘μ΄λ
- μ€μννΈ
- Self
- ν΄μ
- Swift
- observable
- λ°±μ€
- μλ°
- rx
- νλ‘νΌν°
- μλͺ μ£ΌκΈ°
- ν΄λ‘μ
- Today
- Total
study record
[Swift] Noncopyable structs and enums λ³Έλ¬Έ
π« SE-0390Noncopyable structs and enums
Motivation
νμ¬ Swiftμμ μ‘΄μ¬νλ λͺ¨λ νμ μ λ³΅μ¬ κ°λ₯(copyable) νλ―λ‘, ν΄λΉ νμ μ κ°μ λν΄ μ¬λ¬ κ°μ λμΌνκ³ κ΅ν κ°λ₯ν ννμ μμ±ν μ μμ΅λλ€.
νμ§λ§, λ³΅μ¬ κ°λ₯ν ꡬ쑰체(struct)μ μ΄κ±°ν(enum)μ κ³ μ ν μμ(unique resource)μ λͺ¨λΈλ§νλ λ° μ ν©νμ§ μμ΅λλ€.
λ°λ©΄, ν΄λμ€(class)λ κ°μ²΄κ° ν λ² μ΄κΈ°νλλ©΄ κ³ μ ν μ 체μ±(unique identity)μ κ°μ§λ―λ‘ κ³ μ ν μμμ ννν μ μμ΅λλ€. νμ§λ§ ν΄λμ€μ μ°Έμ‘°(reference)λ μ¬μ ν λ³΅μ¬ κ°λ₯νκΈ° λλ¬Έμ, ν΄λμ€λ νμ μμμ 곡μ μμ κΆ(shared ownership)μ μꡬν©λλ€.
μ΄λ¬ν 곡μ μμ κΆμ λ€μκ³Ό κ°μ λΆκ°μ μΈ μ€λ²ν€λλ₯Ό μ΄λν©λλ€.
- κ°μ²΄μ μ 체 μλͺ μ΄ λΆλΆλͺ νκΈ° λλ¬Έμ ν ν λΉ(heap allocation)μ΄ νμν¨
- νμ¬ κ°μ²΄λ₯Ό 곡μ νλ μμ μμ μλ₯Ό μΆμ νκΈ° μν΄ μ°Έμ‘° μΉ΄μ΄ν (reference counting)μ΄ νμν¨
λν, 곡μ μ κ·Ό λ°©μμ κ°μ²΄μ APIλ₯Ό 볡μ‘νκ² λ§λ€κ±°λ, μμ μ± λ¬Έμ λ₯Ό μ΄λνκ±°λ, μΆκ°μ μΈ μ€λ²ν€λλ₯Ό λ°μμν€λ κ²½μ°κ° λ§μ΅λλ€.
νμ¬ Swiftμλ κ³ μ ν μμ κΆ(unique ownership)μ κ°μ§λ κ³ μ ν μμμ νννλ νμ μ μ μνλ λ©μ»€λμ¦μ΄ μ‘΄μ¬νμ§ μμ΅λλ€.
Proposed Solution
μ°λ¦¬λ ꡬ쑰체(struct)μ μ΄κ±°ν(enum) νμ μ΄ noncopyable κ°λ₯νλλ‘ μ μΈν μ μλλ‘ μ μνλ©°, μ΄λ₯Ό μν΄ μλ‘μ΄ λ¬Έλ² ~Copyableμ μ¬μ©νμ¬ μμμ μΈ μ λ€λ¦ μ μ½μ μ΅μ (suppress)νλ λ°©μμ λμ νλ € ν©λλ€.
~Copyableμ μ¬μ©νλ©΄ Swiftκ° μ λ€λ¦ νμ μ΄ μλμΌλ‘ Copyableμ λ°λ₯΄λλ‘ νλ μμμ μΈ μ μ½μ μ κ±°ν μ μλ€.
noncopyable νμ μ κ°μ νμ κ³ μ ν μμ κΆ(unique ownership)μ κ°μ§λ©°, μ λλ‘ λ³΅μ¬λ μ μμ΅λλ€(μ μ΄λ Swiftμ μμμ λ³΅μ¬ λ©μ»€λμ¦μ ν΅ν΄μλ λΆκ°λ₯ν©λλ€).
noncopyable ꡬ쑰체μ μ΄κ±°νμ κ°μ κ³ μ ν μ 체μ±(unique identity)μ κ°μ§λ―λ‘, ν΄λμ€μ²λΌ deinit μ μΈμ κ°μ§ μ μμ΅λλ€. μ΄λ ν΄λΉ κ³ μ μΈμ€ν΄μ€μ μλͺ μ£ΌκΈ°κ° λλ λ μλμΌλ‘ μ€νλ©λλ€.
struct FileDescriptor: **~Copyable** {
private var fd: Int32
init(fd: Int32) { self.fd = fd }
func write(buffer: Data) {
buffer.withUnsafeBytes {
write(fd, $0.baseAddress!, $0.count)
}
}
**deinit** {
close(fd)
}
}
NonCopyable νμ μΌλ‘ μ μΈλμκΈ° λλ¬Έμ,
- κ°μ 볡μ¬ν μ μμ (μ¦, λ κ° μ΄μμ λμΌν FileDescriptor μΈμ€ν΄μ€λ₯Ό λ§λ€ μ μμ)
- κ°μ νμ κ³ μ ν μμ κΆ(unique ownership)μ κ°μ§
- κ°μ΄ 볡μ¬λμ§ μμΌλ―λ‘ κ° μΈμ€ν΄μ€κ° μ μΌν νμΌ νΈλ€μ κ΄λ¦¬
- λΆνμν μ°Έμ‘° μΉ΄μ΄ν (reference counting)κ³Ό 곡μ λΉμ©μ΄ μμ β λΉ λ₯΄κ³ μμ ν μ±λ₯
μ΄μ Swiftμμ ~Copyableμ νμ©νλ©΄ ꡬ쑰체(struct)λ₯Ό ν΅ν΄ κ³ μ ν 리μμ€λ₯Ό μμ νκ³ ν¨μ¨μ μΌλ‘ κ΄λ¦¬ν μ μμ΅λλ€.
- κΈ°μ‘΄μλ ν΄λμ€λ₯Ό μ¬μ©ν΄μΌ νμ§λ§, μ΄μ λ Heap ν λΉ μμ΄, λ μμ νκ³ λΉ λ₯΄κ² κ΄λ¦¬ κ°λ₯
- deinit μ§μμ ν΅ν΄ μλ 리μμ€ ν΄μ κ°λ₯
- λΆνμν λ³΅μ¬ λ°©μ§λ‘ μ±λ₯ μ΅μ ν
λ°λΌμ, ~Copyableμ νμΌ λμ€ν¬λ¦½ν°, λ€νΈμν¬ μμΌ, GPU λ²νΌ κ°μ κ³ μ ν μμ(unique resource)μ κ΄λ¦¬νλ λ° λ§€μ° μ ν©ν κΈ°λ₯μ λλ€.
Noncopyable νμ μ ν¬ν¨νλ κ²½μ°
- ꡬ쑰체(struct)κ° λΉλ³΅μ¬ νμ μ μ μ₯ νλ‘νΌν°(stored property)λ‘ ν¬ν¨νκ±°λ,
- μ΄κ±°ν(enum)μ΄ λΉλ³΅μ¬ νμ μ μ°κ΄ κ°(associated value)μΌλ‘ ν¬ν¨νλ κ²½μ°,
β ν΄λΉ ꡬ쑰체 λλ μ΄κ±°νλ λ°λμ ~Copyableμ μ μΈν΄μΌ ν©λλ€.
μ¦, noncopyable νμ μ ν¬ν¨νλ νμ μμ μλμΌλ‘ noncopyable νμ μ΄ λμ΄μΌ ν©λλ€.
struct SocketPair: ~Copyable {
var in, out: FileDescriptor
}
enum FileOrMemory: ~Copyable {
// write to an OS file
case file(FileDescriptor)
// write to an array in memory
case memory([UInt8])
}
// **ERROR**: **copyable value type cannot contain noncopyable members**
struct FileWithPath {
var file: FileDescriptor
var path: String
}
Classμ noncopyable
Classμ κ²½μ°μλ ~Copyableμ μ±ννμ§ μμλ noncopyable νλ‘νΌν°λ₯Ό κ°μ§ μ μλ€.
class SharedFile {
var file: FileDescriptor
}
ν΄λμ€(class) νμ μ μΈμ ~Copyableμ μ¬μ©ν μ μμ
λͺ¨λ ν΄λμ€ νμ μ μ¬μ ν λ³΅μ¬ κ°λ₯(copyable) νλ©°, ~Copyableμ μ μΈν μ μμ΅λλ€.
μ΄λ ν΄λμ€κ° κ°μ²΄μ λν μ°Έμ‘°(reference)λ₯Ό 볡μ¬ν λ, μ°Έμ‘° μΉ΄μ΄ν (retain/release)μ ν΅ν΄ λ©λͺ¨λ¦¬λ₯Ό κ΄λ¦¬νλ λ°©μ λλ¬Έμ λλ€. μ¦, ν΄λμ€ μΈμ€ν΄μ€ μμ²΄κ° λ³΅μ¬λλ κ²μ΄ μλλΌ κ°μ²΄μ μ°Έμ‘°λ§ λ³΅μ¬λλ―λ‘, ~Copyableμ μ μ©ν νμκ° μμ΅λλ€.
β μ¦, ν΄λμ€λ νμ μ°Έμ‘° νμ (reference type)μ΄λ―λ‘ λ³΅μ¬ κ°λ₯νλ©°, ~Copyableμ μ μ©ν μ μμ΅λλ€.
// **ERROR: classes must be `Copyable`**
class SharedFile: ~Copyable {
var file: FileDescriptor
}
Noncopyable νμ μ΄ μ λ€λ¦ νμ μΈμλ‘ μ¬μ©λ μ μμ
νμ¬ Swiftμ μ λ€λ¦ μμ€ν μ μ λ€λ¦ νμ μ΄ νμ Copyableν κ²μ μꡬν©λλ€.
μ¦, noncopyable νμ (~Copyable)μ μ λ€λ¦ μΈμλ‘ μ λ¬νλ κ²μ λΆκ°λ₯ν©λλ€.
μ΄λ‘ μΈν΄ noncopyable νμ (~Copyable)μ΄ ν μ μλ κ²λ€:
- νλ‘ν μ½ μ€μ λΆκ° (λ¨, Sendableμ μμΈ)β FileDescriptorλ λΉλ³΅μ¬ νμ μ΄λ―λ‘ CustomStringConvertible κ°μ νλ‘ν μ½μ λ°λ₯Ό μ μμ.
- β λ¨, Sendable νλ‘ν μ½μ μμΈμ μΌλ‘ ꡬν κ°λ₯.
- struct FileDescriptor: ~Copyable, CustomStringConvertible { ... } // β λΆκ°λ₯!
- μ λ€λ¦ ν¨μμ νμ μΈμλ‘ μ¬μ© λΆκ°
func process<T>(_ value: T) { ... }
let fd = FileDescriptor(fd: 10)
process(fd) // β λΆκ°λ₯!
- Any λλ λ€λ₯Έ μ‘΄μ¬ νμ (existential)μΌλ‘ μΊμ€ν λΆκ°
let anyValue: Any = FileDescriptor(fd: 10) // β λΆκ°λ₯!
λΉλ³΅μ¬ νμ μ Anyλ λ€λ₯Έ μ‘΄μ¬ νμ μΌλ‘ λ³νν μ μμ.
- β λΉλ³΅μ¬ νμ (~Copyable)μ μ체μ μΌλ‘λ§ μ¬μ© κ°λ₯νλ©°,
- β μ λ€λ¦ μΈμλ‘ μ λ¬νκ±°λ, νλ‘ν μ½μ λ°λ₯΄κ±°λ, Anyλ‘ λ³ννλ λ± λ³΅μ¬κ° κ°λ₯ν 컨ν μ€νΈμμλ μ¬μ© λΆκ°λ₯
β
μ¦, ~Copyableν ꡬ쑰체 λλ μ΄κ±°νμ μ€μ§ μκΈ° μμ λ§ νμ νμ (subtype)μΌλ‘ κ°μ§ μ μμ
λ€λ₯Έ νμ κ³Όμ λ³νμ΄ λΆκ°λ₯νκΈ° λλ¬Έμ 볡μ¬λ₯Ό νμ©νλ 컨ν μ€νΈμμ μ¬μ©λ μ μμ
noncopyable struct μΈμ€ν΄μ€λ₯Ό ν λΉνλ κ² μμ²΄κ° consume
let x = FileDescriptor()
let y = x
use(x) // ERROR: x consumed by assignment to `y`
noncopyable typesμ νλΌλ―Έν°λ‘ μ¬μ© μ, borrowing, consuming, or inout convention μ¬μ© νμ
// Redirect a file descriptor
// Require exclusive access to the FileDescriptor to replace it
func redirect(_ file: inout FileDescriptor, to otherFile: borrowing FileDescriptor) {
dup2(otherFile.fd, file.fd)
}
// **Error: Noncopyable parameter must specify its ownership**
func redirect(_ file: FileDescriptor, to otherFile: borrowing FileDescriptor) {
dup2(otherFile.fd, file.fd)
}
// Write to a file descriptor
// Only needs shared access
func write(_ data: [UInt8], to file: borrowing FileDescriptor) {
data.withUnsafeBytes {
write(file.fd, $0.baseAddress, $0.count)
}
}
// Close a file descriptor
// Consumes the file descriptor
func close(file: consuming FileDescriptor) {
close(file.fd)
}
ν¨μλ λ§μ°¬κ°μ§
extension FileDescriptor {
mutating func replace(with otherFile: borrowing FileDescriptor) {
dup2(otherFile.fd, self.fd)
}
// borrowing by default
func write(_ data: [UInt8]) {
data.withUnsafeBytes {
write(file.fd, $0.baseAddress, $0.count)
}
}
consuming func close() {
close(fd)
}
}
Noncopyable νμ μ νλ‘νΌν° μ μΈ
1. Noncopyable νμ μ μ μ₯ νλ‘νΌν°λ‘ μ μΈ
ν΄λμ€ λλ ~Copyable structλ Noncopyable νμ μ μ μ₯ νλ‘νΌν°(let λλ var)λ‘ μ μΈν μ μλ€.
let μ μ₯ νλ‘νΌν°
- let νλ‘νΌν°λ μ€μ§ borrowλ§ κ°λ₯
- μ¦, μ½μ μλ μμ§λ§ λ³κ²½νκ±°λ consumeν μ μμ
var μ μ₯ νλ‘νΌν°
- var νλ‘νΌν°λ borrowμ mutateλͺ¨λ κ°λ₯
- νμ§λ§ μΌλ°μ μΌλ‘ consumeμ λΆκ°λ₯ (μ νμ μΌλ‘ κ°λ₯)
- μ΄μ : νλ‘νΌν°κ° μλΉλλ©΄ ν΄λΉ μΈμ€ν΄μ€(ꡬ쑰체/ν΄λμ€)κ° λ¬΄ν¨ μνκ° λ μ μκΈ° λλ¬Έ
struct NonCopyableResource: ~Copyable {
var id: Int
}
struct Container: ~Copyable {
let resource: NonCopyableResource // β
let νλ‘νΌν° (borrowλ§ κ°λ₯)
func consumeResource() {
let resourceCopy = move(resource) // β ERROR: 'resource' cannot be consumed because it is immutable
}
func move(_ resource: consuming NonCopyableResource) {
consume resource
}
}
struct Container: ~Copyable {
var resource: NonCopyableResource // β
var νλ‘νΌν° (borrow + mutate κ°λ₯)
mutating func updateResource(id: Int) {
resource.id = id // β
mutate κ°λ₯ (μμ κ°λ₯)
}
func consumeResource() {
let resourceCopy = move(resource) // β ERROR: 'resource' cannot be consumed
}
func move(_ resource: consuming NonCopyableResource) {
consume resource
}
}
2. Noncopyable νμ μ computed νλ‘νΌν°λ‘ μ μΈ
- λͺ¨λ νμ μ Noncopyable νμ μ κ³μ° νλ‘νΌν°λ‘ μ μΈ κ°λ₯
- get μ κ·Όμλ μμ κΆ(owned value)μ λ°νν μ μμ β μ¦, νΈμΆν μͺ½μμ κ°μ consumeν μ μμ
- set μ κ·Όμλ newValueλ₯Ό consumeνλ λ°©μμΌλ‘ λ°μ β μ¦, κΈ°μ‘΄ κ°μ consumeνμ¬ μλ‘μ΄ κ°μΌλ‘ κ΅μ²΄ κ°λ₯
consuming getμ νμ©ν μμ κΆ μ΄μ
- consuming getμ μ¬μ©νλ©΄ μΌλΆ κ°μ μμ κΆκ³Ό ν¨κ» λ°νν μ μμ
- μ΄λ λνΌ(wrapper) νμ μμ λ΄λΆ κ°μ μμ κΆμ λ겨주λ λ°©μμΌλ‘ μ μ©
struct FileDescriptorWrapper: ~Copyable {
private var _value: FileDescriptor
var value: FileDescriptor { // 'self' is borrowed and cannot be consumed ?!
consuming get { return _value }
}
}
Classμμ Noncopyable μ μ₯ νλ‘νΌν° μ¬μ©
1) ν΄λμ€μ μ μ₯ νλ‘νΌν°μ λμ λ°°νμ± κ²μ¬(Dynamic Exclusivity Checking)
Swiftμμλ κ°μ²΄(Class Instance)κ° μ¬λ¬ μ°Έμ‘°(reference)λ₯Ό κ°μ§ μ μκΈ° λλ¬Έμ,
λμμ κ°μ μ μ₯ νλ‘νΌν°λ₯Ό μμ νλ κ²μ λ°©μ§νκΈ° μν΄ "λμ λ°°νμ± κ²μ¬(Dynamic Exclusivity Checking)"λ₯Ό μνν©λλ€.
μ΄ λμ κ²μ¬(runtime check)λ ~Copyable μ μ₯ νλ‘νΌν°μλ μ μ©λ©λλ€.
μ¦, λμμ borrow(λμ¬)μ mutate(λ³κ²½)κ° μλλλ©΄, λ°νμ μ€λ₯κ° λ°μν μ μμ΅λλ€.
Swiftλ borrow μνμμ mutateκ° λΆκ°λ₯νλλ‘ κ°μ ν¨
class Foo {
var fd: FileDescriptor
init(fd: FileDescriptor) { self.fd = fd }
}
func update(_: inout FileDescriptor, butBorrow _: borrow FileDescriptor) {}
func updateFoo(_ a: Foo, butBorrowFoo b: Foo) {
update(&a.fd, butBorrow: b.fd)
}
let foo = Foo(fd: FileDescriptor())
// Will trap at runtime when foo.fd is borrowed and mutated at the same time
updateFoo(foo, butBorrowFoo: foo)
Noncopyable λ³μκ° escaping ν΄λ‘μ μμ μΊ‘μ²λ λμ λμ
nonescaping vs. escaping ν΄λ‘μ μμ Noncopyable λ³μ μΊ‘μ² μ°¨μ΄
- nonescaping ν΄λ‘μ λ μ ν¨ λ²μ(scope)κ° νμ λ¨ β λ°λΌμ λ³μλ₯Ό borrow(λμ¬)ν μ μμ
- escaping ν΄λ‘μ λ νλ‘κ·Έλ¨μ΄ μ€νλλ λμ μΈμ λ μ§ νΈμΆλ μ μμ β λ°λΌμ λ³μμ μμ κΆμ λͺ ννκ² κ΄λ¦¬ν΄μΌ ν¨
π‘ μ¦, escaping ν΄λ‘μ μμ Noncopyable λ³μλ₯Ό μΊ‘μ²νλ©΄, λ³μλ νμ borrow μνκ° λλ©° consume(μλΉ)ν μ μμ
- escaping ν΄λ‘μ λ νμ¬ μ€μ½νλ₯Ό λ²μ΄λμλ μ€νλ μ μμ
- μΌλ°μ μΌλ‘ Swiftμ Copyableν κ°λ€μ escaping ν΄λ‘μ μμ μμ νκ² λ³΅μ¬ κ°λ₯
- νμ§λ§ λΉλ³΅μ¬(~Copyable) λ³μλ 볡μ¬ν μ μμΌλ―λ‘, consumeνλ©΄ μλ³Έμ΄ μ¬λΌμ§
π¨ μ¦, consumeνλ©΄ λ³μκ° λ μ΄μ μ‘΄μ¬νμ§ μμΌλ―λ‘, μ΄ν μ€νλ ν΄λ‘μ μμ ν΄λΉ λ³μλ₯Ό μ¬μ©ν μ μμ
import Dispatch
struct FileDescriptor: ~Copyable {
private var fd: Int32
init(fd: Int32) { self.fd = fd }
func read() {
print("Reading from fd: \\(fd)")
}
consuming func close() {
print("Closing fd: \\(fd)")
}
}
func escape(_ closure: @escaping () -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
closure()
}
}
func test() {
let file = FileDescriptor(fd: 42)
escape {
file.read() // β
`borrow` κ°λ₯ (μ½κΈ° μ μ©)
// file.close() // β ERROR: `file`μ `escaping` ν΄λ‘μ μμ `borrow` μνμ΄λ―λ‘ `consume` λΆκ°
}
}
test()
ꡬ쑰체(struct) λ° μ΄κ±°ν(enum)μ deinit νΉμ§
- ν΄λμ€μ deinitκ³Ό λ§μ°¬κ°μ§λ‘, struct λ° enumμ deinitμμλ μ€λ₯λ₯Ό λμ§ μ μμ
- deinit λ΄λΆμμ selfλ borrow μν
- μ¦, mutate(λ³κ²½)νκ±°λ consume(μλΉ)ν μ μμ
struct FileDescriptor: ~Copyable {
private var fd: Int32
init(fd: Int32) { self.fd = fd }
deinit {
print("Closing file descriptor \\(fd)")
// self.fd = -1 β ERROR: `deinit` λ΄λΆμμλ `mutate` λΆκ°
// consume self β ERROR: `deinit` λ΄λΆμμλ `consume` λΆκ°
}
}
λ°κΉ₯ ~Copyableμ΄ λ¨Όμ deinit λ¨.
struct Inner: ~Copyable {
deinit { print("destroying inner") }
}
struct Outer: ~Copyable {
var inner = Inner()
deinit { print("destroying outer") }
}
do {
_ = Outer()
}
// destroying outer
// destroying inner
discard selfλ₯Ό νμ©νμ¬ deinit μ€ν μ΅μ
Noncopyable νμ μμ deinitμ΄ μ€νλμ§ μλλ‘ νκΈ° μν΄ discard self μ°μ°μλ₯Ό λμ
- discard selfλ ν΄λΉ κ°μ²΄(self)μ μλͺ μ μ’ λ£νμ§λ§, deinitμ νΈμΆνμ§ μμ
- μ΄λ₯Ό ν΅ν΄ 리μμ€λ₯Ό μ§μ μ μ΄ κ°λ₯
struct FileDescriptor: ~Copyable {
private var fd: Int32
deinit {
close(fd)
}
consuming func close() {
close(fd)
// The lifetime of `self` ends here, triggering `deinit` (and another call to `close`)!
}
}
struct FileDescriptor: ~Copyable {
private var fd: Int32
// νμΌ λμ€ν¬λ¦½ν°λ₯Ό λ«μ λ, `deinit`μ΄ μ€νλμ§ μλλ‘ μ΅μ
consuming func close() throws {
if close(fd) != 0 {
throw CloseError(errno)
}
discard self // β
`deinit`μ΄ μ€νλμ§ μμ
}
}
쑰건λΆλ‘ deinitμ μ€νν μ§ μ¬λΆλ₯Ό κ²°μ κ°λ₯
β discard selfλ₯Ό μ¬μ©νλ©΄ deinitμ΄ μ€νλμ§ μκ³ , consume selfλ₯Ό μ¬μ©νλ©΄ deinit μ€νλ¨
struct MemoryBuffer: ~Copyable {
private var address: UnsafeRawPointer
init(size: Int) throws {
guard let address = malloc(size) else {
throw MallocError()
}
self.address = address
}
deinit {
free(address)
}
consuming func takeOwnership(if condition: Bool) -> UnsafeRawPointer? {
if condition {
// Save the memory buffer and give it to the caller, who
// is promising to free it when they're done.
let address = self.address
**discard self**
return address
} else {
// We still want to free the memory if we aren't giving it away.
**_ = consume self**
return nil
}
}
}
'Swift' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Swift] consume, consuming, borrowing (0) | 2025.03.03 |
---|