SwiftのStructの参照渡し、値渡し、CoWの挙動確認
結論
- クロージャへは参照渡し、キャプチャリストを使えば値渡し
- 関数へは値渡し、inoutを使えば参照渡し
Copy-on-Write (CoW)
- SwiftのArrayやStringはパフォーマンスを考慮して、内部的にCoWが実装されている
確認
環境
- Xcode 9.4
- Swift 4.1
Playground
import Foundation
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
func printLine(_ line: Int = #line) {
print("#L\(line)")
}
print("--- Clousure: Int ---\n")
do {
var value = 10
let closure1 = {
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
let closure2 = { [value] in
print("- value = \(value) ← 値渡しなので影響を受けない") // valueは値渡し
}
let closure3 = {
value += 10
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 10
printLine()
closure1() // value = 10
printLine()
value = 20
print("- value = \(value) (\(address(of: &value)))")
closure1() // value = 20 (参照渡しなので反映されている)
printLine()
closure2() // value = 10 (値渡しなので反映されていない)
printLine()
closure3() // value = 30
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 30 (closure3での変更が反映されている)
}
print("\n--- Clousure: [Int] ---\n")
do {
var values = [10]
let closure1 = {
print("- values = \(values) (\(address(of: &values)))") // valueは参照渡し
}
let closure2 = { [values] in
print("- values = \(values) ← 値渡しなので影響を受けない") // valueは値渡し
}
let closure3 = {
values.append(values.last! + 10) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // valueは参照渡し
}
printLine()
print("- values = \(values) (\(address(of: &values)))")
printLine()
closure1() // values = [10]
printLine()
values.append(20) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // values = [10, 20]
closure1() // values = [10, 20] (参照渡しなので反映されている)
printLine()
closure2() // values = [10] (値渡しなので反映されていない)
printLine()
closure3() // value = [10, 20, 30]
printLine()
print("- values = \(values) (\(address(of: &values)))") // value = [10, 20, 30] (closure3での変更が反映)
}
print("\n--- Function: Int ---\n")
do {
var value = 10
func function1(_ value: inout Int) {
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
func function2( _ value: Int) {
print("- value = \(value) ← 値渡しなので影響を受けない") // valueは値渡し
}
func function3(_ value: inout Int) {
value += 10
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 10
printLine()
function1(&value) // value = 10
printLine()
value = 20
print("- value = \(value) (\(address(of: &value)))") // value = 20
printLine()
function3(&value) // value = 30
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 30 (function3での変更が反映されている)
}
print("\n--- Function: [Int] ---\n")
do {
var values = [10]
func function1(_ values: inout [Int]) {
print("- values = \(values) (\(address(of: &values)))") // valuesは参照渡し
}
func function2( _ values: [Int]) {
print("- values = \(values) ← 値渡しなので影響を受けない") // valuesは値渡し
}
func function3(_ values: inout [Int]) {
values.append(values.last! + 10) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // valuesは参照渡し
}
printLine()
print("- values = \(values) (\(address(of: &values)))") // values = [10]
printLine()
function1(&values) // values = [10]
printLine()
values.append(20) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // values = [10, 20]
printLine()
function3(&values) // value = [10, 20, 30]
printLine()
print("- values = \(values) (\(address(of: &values)))") // values = [10, 20, 30] (function3での変更が反映)
}
結果
--- Clousure: Int ---
#L31
- value = 10 (0x608000021d90)
#L34
- value = 10 (0x608000021d90)
#L37
- value = 20 (0x608000021d90)
- value = 20 (0x608000021d90)
#L42
- value = 10 ← 値渡しなので影響を受けない
#L45
- value = 30 (0x608000021d90)
#L48
- value = 30 (0x608000021d90)
--- Clousure: [Int] ---
#L69
- values = [10] (0x600000054ed0)
#L72
- values = [10] (0x600000054ed0)
#L75
- values = [10, 20] (0x60c0000553b0) ← CoWによりバッファへのポインタが変更されていることが確認できる
- values = [10, 20] (0x60c0000553b0)
#L80
- values = [10] ← 値渡しなので影響を受けない
#L83
- values = [10, 20, 30] (0x60c00006aba0) ← CoWによりバッファへのポインタが変更されていることが確認できる
#L86
- values = [10, 20, 30] (0x60c00006aba0)
--- Function: Int ---
#L107
- value = 10 (0x7ffeeaabede8)
#L110
- value = 10 (0x7ffeeaabede8)
#L113
- value = 20 (0x7ffeeaabede8)
#L117
- value = 30 (0x7ffeeaabede8)
#L120
- value = 30 (0x7ffeeaabede8)
--- Function: [Int] ---
#L141
- values = [10] (0x60c000056160)
#L144
- values = [10] (0x60c000056160)
#L147
- values = [10, 20] (0x604000055410) ← CoWによりバッファへのポインタが変更されていることが確認できる
#L151
- values = [10, 20, 30] (0x604000066b60) ← CoWによりバッファへのポインタが変更されていることが確認できる
#L154
- values = [10, 20, 30] (0x604000066b60)
参考
環境
- Xcode 9.4
- Swift 4.1
Playground
import Foundation
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
func printLine(_ line: Int = #line) {
print("#L\(line)")
}
print("--- Clousure: Int ---\n")
do {
var value = 10
let closure1 = {
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
let closure2 = { [value] in
print("- value = \(value) ← 値渡しなので影響を受けない") // valueは値渡し
}
let closure3 = {
value += 10
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 10
printLine()
closure1() // value = 10
printLine()
value = 20
print("- value = \(value) (\(address(of: &value)))")
closure1() // value = 20 (参照渡しなので反映されている)
printLine()
closure2() // value = 10 (値渡しなので反映されていない)
printLine()
closure3() // value = 30
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 30 (closure3での変更が反映されている)
}
print("\n--- Clousure: [Int] ---\n")
do {
var values = [10]
let closure1 = {
print("- values = \(values) (\(address(of: &values)))") // valueは参照渡し
}
let closure2 = { [values] in
print("- values = \(values) ← 値渡しなので影響を受けない") // valueは値渡し
}
let closure3 = {
values.append(values.last! + 10) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // valueは参照渡し
}
printLine()
print("- values = \(values) (\(address(of: &values)))")
printLine()
closure1() // values = [10]
printLine()
values.append(20) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // values = [10, 20]
closure1() // values = [10, 20] (参照渡しなので反映されている)
printLine()
closure2() // values = [10] (値渡しなので反映されていない)
printLine()
closure3() // value = [10, 20, 30]
printLine()
print("- values = \(values) (\(address(of: &values)))") // value = [10, 20, 30] (closure3での変更が反映)
}
print("\n--- Function: Int ---\n")
do {
var value = 10
func function1(_ value: inout Int) {
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
func function2( _ value: Int) {
print("- value = \(value) ← 値渡しなので影響を受けない") // valueは値渡し
}
func function3(_ value: inout Int) {
value += 10
print("- value = \(value) (\(address(of: &value)))") // valueは参照渡し
}
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 10
printLine()
function1(&value) // value = 10
printLine()
value = 20
print("- value = \(value) (\(address(of: &value)))") // value = 20
printLine()
function3(&value) // value = 30
printLine()
print("- value = \(value) (\(address(of: &value)))") // value = 30 (function3での変更が反映されている)
}
print("\n--- Function: [Int] ---\n")
do {
var values = [10]
func function1(_ values: inout [Int]) {
print("- values = \(values) (\(address(of: &values)))") // valuesは参照渡し
}
func function2( _ values: [Int]) {
print("- values = \(values) ← 値渡しなので影響を受けない") // valuesは値渡し
}
func function3(_ values: inout [Int]) {
values.append(values.last! + 10) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // valuesは参照渡し
}
printLine()
print("- values = \(values) (\(address(of: &values)))") // values = [10]
printLine()
function1(&values) // values = [10]
printLine()
values.append(20) // CoW
print("- values = \(values) (\(address(of: &values))) ← CoWによりバッファへのポインタが変更されていることが確認できる") // values = [10, 20]
printLine()
function3(&values) // value = [10, 20, 30]
printLine()
print("- values = \(values) (\(address(of: &values)))") // values = [10, 20, 30] (function3での変更が反映)
}
結果
--- Clousure: Int ---
#L31
- value = 10 (0x608000021d90)
#L34
- value = 10 (0x608000021d90)
#L37
- value = 20 (0x608000021d90)
- value = 20 (0x608000021d90)
#L42
- value = 10 ← 値渡しなので影響を受けない
#L45
- value = 30 (0x608000021d90)
#L48
- value = 30 (0x608000021d90)
--- Clousure: [Int] ---
#L69
- values = [10] (0x600000054ed0)
#L72
- values = [10] (0x600000054ed0)
#L75
- values = [10, 20] (0x60c0000553b0) ← CoWによりバッファへのポインタが変更されていることが確認できる
- values = [10, 20] (0x60c0000553b0)
#L80
- values = [10] ← 値渡しなので影響を受けない
#L83
- values = [10, 20, 30] (0x60c00006aba0) ← CoWによりバッファへのポインタが変更されていることが確認できる
#L86
- values = [10, 20, 30] (0x60c00006aba0)
--- Function: Int ---
#L107
- value = 10 (0x7ffeeaabede8)
#L110
- value = 10 (0x7ffeeaabede8)
#L113
- value = 20 (0x7ffeeaabede8)
#L117
- value = 30 (0x7ffeeaabede8)
#L120
- value = 30 (0x7ffeeaabede8)
--- Function: [Int] ---
#L141
- values = [10] (0x60c000056160)
#L144
- values = [10] (0x60c000056160)
#L147
- values = [10, 20] (0x604000055410) ← CoWによりバッファへのポインタが変更されていることが確認できる
#L151
- values = [10, 20, 30] (0x604000066b60) ← CoWによりバッファへのポインタが変更されていることが確認できる
#L154
- values = [10, 20, 30] (0x604000066b60)
参考
Author And Source
この問題について(SwiftのStructの参照渡し、値渡し、CoWの挙動確認), 我々は、より多くの情報をここで見つけました https://qiita.com/yusuga/items/4983b5282de195c39d35著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .