私はSwiftを本当に使い始めたばかりで、クラスが参照によって渡され、配列や文字列などがコピーされることを読んだだけです。
参照渡しは、Objective-CまたはJavaと同じ方法で実際に「a」参照を渡しますか、それとも適切な参照渡しですか?
私はSwiftを本当に使い始めたばかりで、クラスが参照によって渡され、配列や文字列などがコピーされることを読んだだけです。
参照渡しは、Objective-CまたはJavaと同じ方法で実際に「a」参照を渡しますか、それとも適切な参照渡しですか?
回答:
ルールは:
クラスのインスタンスは、参照型(つまりは、あなたのクラスのインスタンスへの参照が効果的であるポインタ)
関数は参照型です
それ以外はすべて値型です。「その他すべて」とは、構造体のインスタンスと列挙型のインスタンスを単に意味します。それは、Swiftにあるすべてのことだからです。たとえば、配列と文字列は構造体インスタンスです。newacctが指摘したように、アドレスを使用して取得することにより、(関数の引数として)それらの1 つへの参照を渡すことができinout
ます。しかし、型自体は値型です。
参照型オブジェクトは、次の理由により実際には特別です。
関数への単なる割り当てまたは受け渡しは、同じオブジェクトへの複数の参照をもたらす可能性があります
オブジェクトへの参照が定数(let
明示的または暗黙的)であっても、オブジェクト自体は変更可能です。
オブジェクトへのすべての参照からわかるように、オブジェクトへの変更はそのオブジェクトに影響します。
これらは危険な場合があるので、目を離さないでください。一方、参照型の受け渡しは、ポインタのみがコピーされて受け渡されるため、非常に効率的であることは明らかです。
明らかに、値の型を渡すことは「より安全」であり、それがlet
意味することを意味しlet
ます。参照を通じて構造体インスタンスまたは列挙型インスタンスを変更することはできません。一方、その安全性は価値のコピーを別に作ることで実現しませんか?それは値の型を渡すことを潜在的に高価にしませんか?
まあ、はい、いいえ。それはあなたが思うほど悪くはありません。ネイトクックが言ったように、値の型を渡すことは必ずしもコピーを意味するわけではありません。なぜなら、let
(明示的または暗黙的に)不変性が保証されるため、何もコピーする必要はありません。var
参照に渡しても、コピーされることを意味するのではなく、必要に応じてコピーが可能になるだけです(変異があるため)。ドキュメントは、特にひねりを加えないようにアドバイスしています。
inout
タイプに関係ない場合、値渡しです。何かが参照渡しであるかどうかは、タイプに直交しています。
パラメータがでない場合は、常に 値渡しinout
です。
パラメータがの場合、これは常に 参照渡しですinout
。ただし、パラメーター&
に渡すときに引数に演算子を明示的に使用する必要があるため、これはやや複雑なinout
ので、変数を直接渡す従来の参照渡しの定義に適合しない場合があります。
inout
inout
実際には参照渡しではなく、コピーインコピーアウトです。これは、関数呼び出しの後に変更された値が元の引数に割り当てられることを保証するだけです。In-Outパラメータ
Swiftのすべてはデフォルトで「コピー」によって渡されるため、値タイプを渡すと値のコピーが取得され、参照タイプを渡すと参照のコピーが取得されます。(つまり、参照のコピーは依然として元の参照と同じインスタンスを指しています)。
Swiftは多くの最適化を行うため、上記の「コピー」の周りに怖い引用を使用しています。可能な限り、変異または変異の可能性があるまでコピーしません。パラメータはデフォルトで不変であるため、ほとんどの場合、実際にはコピーは発生しません。
以下は、参照渡しの小さなコードサンプルです。強い理由がない限り、これは避けてください。
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);
inout
コピーイン、コピーアウト演算子です。最初にオブジェクトをコピーし、関数が戻った後に元のオブジェクトを上書きします。同じように見えるかもしれませんが、微妙な違いがあります。
アップルスウィフト開発者ブログは、ポストと呼ばれた値と基準タイプこの非常にトピックに関する明確かつ詳細な議論を提供します。
引用するには:
Swiftの型は2つのカテゴリのいずれかに分類されます。1つは「値型」で、各インスタンスはデータの一意のコピーを保持します。通常、構造体、列挙型、またはタプルとして定義されます。2番目の「参照型」では、インスタンスがデータの単一のコピーを共有し、型は通常クラスとして定義されます。
Swiftブログの投稿では、例の違いを引き続き説明し、どちらを使用するかを提案しています。
デフォルトでは、クラスは参照によって渡され、その他は値によって渡されます。inout
キーワードを使用して参照渡しすることができます。
inout
コピーイン、コピーアウト演算子です。最初にオブジェクトをコピーし、関数が戻った後に元のオブジェクトを上書きします。同じように見えるかもしれませんが、微妙な違いがあります。
+ =などのinfix演算子でinoutを使用する場合、&addressシンボルは無視できます。コンパイラは参照渡しを想定していますか?
extension Dictionary {
static func += (left: inout Dictionary, right: Dictionary) {
for (key, value) in right {
left[key] = value
}
}
}
origDictionary + = newDictionaryToAdd
そして、この辞書「add」は元の参照への書き込みも1回だけなので、ロックに最適です。
クラスと構造
構造体とクラスの最も重要な違いの1つは、構造体はコード内で渡されるときに常にコピーされますが、クラスは参照によって渡されることです。
閉鎖
クラスインスタンスのプロパティにクロージャーを割り当て、クロージャーがインスタンスまたはそのメンバーを参照することによってそのインスタンスをキャプチャする場合、クロージャーとインスタンスの間に強い参照サイクルが作成されます。Swiftはキャプチャリストを使用して、これらの強力な参照サイクルを壊します
ARC(自動参照カウント)
参照カウントは、クラスのインスタンスにのみ適用されます。構造体と列挙型は値型であり、参照型ではなく、格納されて参照によって渡されることはありません。