迅速な値渡しまたは参照渡し


100

私はSwiftを本当に使い始めたばかりで、クラ​​スが参照によって渡され、配列や文字列などがコピーされることを読んだだけです。

参照渡しは、Objective-CまたはJavaと同じ方法で実際に「a」参照を渡しますか、それとも適切な参照渡しですか?


「参照渡しはObjective-CまたはJavaと同じ方法です」Objective-CもJavaも参照渡しではありません。
newacct 2014

2
はい。そんなこと知ってる。参照渡ししないでください。参照は値で渡します。答えるときそれはわかっていたと思いました。
gran_profaci 2014

Javaは参照ではなく値で渡します。
6

回答:


167

スウィフトのタイプ

ルールは:

  • クラスのインスタンスは、参照型(つまりは、あなたのクラスのインスタンスへの参照が効果的であるポインタ

  • 関数は参照型です

  • それ以外はすべて値型です。「その他すべて」とは、構造体のインスタンスと列挙型のインスタンスを単に意味します。それは、Swiftにあるすべてのことだからです。たとえば、配列と文字列は構造体インスタンスです。newacctが指摘したように、アドレスを使用して取得することにより、(関数の引数として)それらの1 つへの参照を渡すことができinoutます。しかし、型自体は値型です。

参照タイプの意味

参照型オブジェクトは、次の理由により実際には特別です。

  • 関数への単なる割り当てまたは受け渡しは、同じオブジェクトへの複数の参照をもたらす可能性があります

  • オブジェクトへの参照が定数(let明示的または暗黙的)であっても、オブジェクト自体は変更可能です。

  • オブジェクトへのすべての参照からわかるように、オブジェクトへの変更はそのオブジェクトに影響します。

これらは危険な場合があるので、目を離さないでください。一方、参照型の受け渡しは、ポインタのみがコピーされて受け渡されるため、非常に効率的であることは明らかです。

あなたにとってどんな値型が意味するか

明らかに、値の型を渡すことは「より安全」であり、それがlet意味することを意味しletます。参照を通じて構造体インスタンスまたは列挙型インスタンスを変更することはできません。一方、その安全性は価値のコピーを別に作ることで実現しませんか?それは値の型を渡すことを潜在的に高価にしませんか?

まあ、はい、いいえ。それはあなたが思うほど悪くはありません。ネイトクックが言ったように、値の型を渡すことは必ずしもコピーを意味するわけではありません。なぜなら、let(明示的または暗黙的に)不変性が保証されるため、何もコピーする必要はありません。var参照に渡しても、コピーれること意味するのではなく、必要に応じてコピーが可能になるだけです(変異があるため)。ドキュメントは、特にひねりを加えないようにアドバイスしています。


6
「クラスインスタンスは参照渡しされます。関数は参照渡しされます」いいえ。パラメータがinoutタイプに関係ない場合、値渡しです。何かが参照渡しであるかどうかは、タイプに直交しています。
newacct 2014

4
@newacctさて、もちろんあなたは厳密な意味で正しいです!厳密には、すべてが値渡しであるが、列挙型インスタンスと構造体インスタンスは値型であり、クラスインスタンスと関数は参照型であると言う必要があります。たとえば、developer.apple.com / swift / blog /?id = 10を参照してください。developer.apple.com/ library / ios / documentation / Swift / Conceptual /も参照してください。しかし、私が言ったことは、言葉の意味は意味します。
マット

6
正しく、値の型/参照型は、値渡しまたは参照渡しと混同しないでください。値型は、値または参照によって渡すことができ、参照型は、値または参照によって渡すこともできます。
newacct 2014

1
@newacctは非常に役立つディスカッションです。誤解を招かないように要約を書き直しています。
マット

43

パラメータがでない場合は、常に 値渡しinoutです。

パラメータがの場合、これは常に 参照渡しですinout。ただし、パラメーター&に渡すときに引数に演算子を明示的に使用する必要があるため、これはやや複雑なinoutので、変数を直接渡す従来の参照渡しの定義に適合しない場合があります。


3
この答えは、ネイトクックと組み合わせると、(参照型)を明示的に(を使用して)指定しない限り、関数のスコープ外で変更されないという事実に関して(C ++から)私にとってより明確でしたinout
Gobe

10
inout実際には参照渡しではなく、コピーインコピーアウトです。これは、関数呼び出しの後に変更された値が元の引数に割り当てられることを保証するだけです。In-Outパラメータ
Dalija Prasnikar 2017

すべてが値で渡されることは事実ですが。参照タイプのプロパティは、同じインスタンスへのコピー参照として関数内で変更できます。
MrAn3

42

Swiftのすべてはデフォルトで「コピー」によって渡されるため、値タイプを渡すと値のコピーが取得され、参照タイプを渡すと参照のコピーが取得されます。(つまり、参照のコピーは依然として元の参照と同じインスタンスを指しています)。

Swiftは多くの最適化を行うため、上記の「コピー」の周りに怖い引用を使用しています。可能な限り、変異または変異の可能性があるまでコピーしません。パラメータはデフォルトで不変であるため、ほとんどの場合、実際にはコピーは発生しません。


私にとってこれは最良の答えです。たとえば、インスタンスのプロパティは、同じ参照を指すため、パラメーターがコピー(値渡し)であっても、関数内で変更できることが明らかになりました。
MrAn3

9

以下は、参照渡しの小さなコードサンプルです。強い理由がない限り、これは避けてください。

func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
    value1 = "my great computation 1";
    value2 = 123456;
}

このように呼ぶ

var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);

なぜこれを避けるべきですか?
脳のない

1
@Brainlessは、コードに不必要な複雑さを追加するためです。パラメータを取り込んで、単一の結果を返すのが最善です。これを行わなければならないことは、通常、設計が不十分であることを示しています。別の言い方をすると、渡された参照変数に隠された副作用は、呼び出し元には透過的ではありません。
Chris Amelinckx

これは参照渡しされません。inoutコピーイン、コピーアウト演算子です。最初にオブジェクトをコピーし、関数が戻った後に元のオブジェクトを上書きします。同じように見えるかもしれませんが、微妙な違いがあります。
Hannes Hertach

7

アップルスウィフト開発者ブログは、ポストと呼ばれた値と基準タイプこの非常にトピックに関する明確かつ詳細な議論を提供します。

引用するには:

Swiftの型は2つのカテゴリのいずれかに分類されます。1つは「値型」で、各インスタンスはデータの一意のコピーを保持します。通常、構造体、列挙型、またはタプルとして定義されます。2番目の「参照型」では、インスタンスがデータの単一のコピーを共有し、型は通常クラスとして定義されます。

Swiftブログの投稿では、例の違いを引き続き説明し、どちらを使用するかを提案しています。


1
これは質問の答えにはなりません。問題は、値の型と参照の型に対して完全に直交する値渡しと参照渡しについてです。
イェルクWミッターク

2

デフォルトでは、クラスは参照によって渡され、その他は値によって渡されます。inoutキーワードを使用して参照渡しすることができます。


これは誤りです。inoutコピーイン、コピーアウト演算子です。最初にオブジェクトをコピーし、関数が戻った後に元のオブジェクトを上書きします。同じように見えるかもしれませんが、微妙な違いがあります。
Hannes Hertach

2

+ =などのinfix演算子でinoutを使用する場合、&addressシンボルは無視できます。コンパイラは参照渡しを想定していますか?

extension Dictionary {
    static func += (left: inout Dictionary, right: Dictionary) {
        for (key, value) in right {
            left[key] = value
        }
    }
}

origDictionary + = newDictionaryToAdd

そして、この辞書「add」は元の参照への書き込みも1回だけなので、ロックに最適です。


2

クラスと構造

構造体とクラスの最も重要な違いの1つは、構造体はコード内で渡されるときに常にコピーされますが、クラスは参照によって渡されることです。

閉鎖

クラスインスタンスのプロパティにクロージャーを割り当て、クロージャーがインスタンスまたはそのメンバーを参照することによってそのインスタンスをキャプチャする場合、クロージャーとインスタンスの間に強い参照サイクルが作成されます。Swiftはキャプチャリストを使用して、これらの強力な参照サイクルを壊します

ARC(自動参照カウント)

参照カウントは、クラスのインスタンスにのみ適用されます。構造体と列挙型は値型であり、参照型ではなく、格納されて参照によって渡されることはありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.