私は本当にSwiftが初めてで、クラスが参照によって渡され、配列/文字列などがコピーされることを読んだばかりです。
参照による受け渡しは、Objective-CまたはJavaの場合と同じ方法で、実際に「a」参照を渡しますか、それとも適切な参照渡しですか?
ルールは次のとおりです。
クラスインスタンスは参照タイプ(つまりyourクラスインスタンスへの参照は実質的にpointer)です
関数は参照型です
それ以外はすべて値型; 「他のすべて」とは、構造体のインスタンスと列挙型のインスタンスを意味するだけです。Swiftにはそれがすべてあるからです。たとえば、配列と文字列は構造体インスタンスです。 can newacctが指摘しているように、inout
を使用してアドレスを取得することにより、それらの1つへの参照を(関数の引数として)渡します。ただし、型自体は値型です。
参照型オブジェクトは、実際には特別です:
単なる代入または関数への受け渡しにより、同じオブジェクトへの複数の参照が生成される場合があります
オブジェクトへの参照が定数(let
、明示的または暗黙的)であっても、オブジェクト自体は可変です。
オブジェクトへのすべての参照で見られるように、オブジェクトへの突然変異はそのオブジェクトに影響します。
これらは危険な可能性があるため、注意してください。一方、参照型を渡すことは、ポインタのみがコピーされて渡されるため、明らかに効率的です。これは簡単です。
明らかに、値の型を渡すことは「より安全」であり、let
はそれが言うことを意味します:let
参照を介してstructインスタンスまたはenumインスタンスを変更することはできません。一方、その安全性は値のコピーを別に作成することで達成されますよね?値型を渡すことは潜在的に高価ではありませんか?
はい、そうです。思っているほど悪くはありません。 Nate Cookが言ったように、値型を渡すことは必然的にコピーを意味しません。let
(明示的または暗黙的)は不変性を保証するため、何もコピーする必要はありません。 var
参照に渡しても、物事がコピーされることを意味するわけではありませんwillは、必要に応じてcanがコピーされるということだけです(突然変異があるため)。ドキュメントは、あなたのニッカーズをひねってはいけないことを特にアドバイスしています。
パラメーターがinout
でない場合、alwayspass-by-valueです。
パラメーターがinout
の場合、alwayspass-by-referenceです。ただし、これは、inout
パラメータに渡すときに引数で&
演算子を明示的に使用する必要があるため、多少複雑です。したがって、参照渡しの従来の定義に適合しない場合があります。変数を直接渡す場所。
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);
Apple Swift Developerブログには、Value and Reference Types)という投稿がありますこのトピックに関する明確で詳細な議論を提供します。
引用するには:
Swiftの型は2つのカテゴリのいずれかに分類されます。まず、「値型」。各インスタンスは、通常、構造体、列挙、またはタプルとして定義されるデータの一意のコピーを保持します。 2番目の「参照型」では、インスタンスがデータの単一のコピーを共有します。通常、型はクラスとして定義されます。
Swiftブログ投稿では、例との違いを引き続き説明し、どちらを使用するかを提案しています。
クラスは参照によって渡され、その他はデフォルトで値によって渡されます。 inout
キーワードを使用して、参照渡しできます。
+ =などの挿入演算子を使用してinoutを使用する場合、&addressシンボルは無視できます。コンパイラは参照渡しを前提としていますか?
extension Dictionary {
static func += (left: inout Dictionary, right: Dictionary) {
for (key, value) in right {
left[key] = value
}
}
}
origDictionary + = newDictionaryToAdd
また、この辞書「追加」は元の参照への書き込みも1回しか行わないため、ロックに最適です!
クラスと構造体
構造体とクラスの最も重要な違いの1つは、構造体がコードで渡されるときに常にコピーされるが、クラスは参照によって渡されることです。
クロージャ
クラスインスタンスのプロパティにクロージャーを割り当て、クロージャーがインスタンスまたはそのメンバーを参照してそのインスタンスをキャプチャする場合、クロージャーとインスタンスの間に強力な参照サイクルを作成します。 Swiftはキャプチャリストを使用して、これらの強い参照サイクルを破ります
ARC(自動参照カウント)
参照カウントは、クラスのインスタンスにのみ適用されます。構造と列挙は、参照型ではなく値型であり、参照によって格納および渡されることはありません。