2017-08-10 6 views
3

私はC++を学び始めましたが、今はSwiftでもいくつかのことができるかどうか疑問に思っています。Swiftのリファレンス変数を渡す

私はSwiftの関数に変数として引数を渡したときに何が起こったのか考えたことはありませんでした。

例として、変数stringを使用してみましょう。

C++では、関数の引数をコピーするか、参照/ポインタで引数を渡すことができます。

void foo(string s)またはvoid foo (string& s); 第1のケースでは、元の変数のコピーが作成され、fooにコピーが送られます。 2番目のケースでは、私は基本的に、コピーを作成せずにメモリ内の変数のアドレスを渡します。

スウィフトでは、関数への引数をinoutと宣言できます。これは、元のオブジェクトを変更できることを意味します。結果は、私は予想されなかったこと

extension String { 
    func address() -> String { 
     return String(format: "%p", self); 
    } 
} 

1)func foo(s:String) ... 2)func testPassingByReference(s: inout String) ...

私はオブジェクトのアドレスを印刷する文字列を拡張しました見る。

var str = "Hello world" 
print(str.address()) 

0x7fd6c9e04ef0

func testPassingByValue(s: String) { 
    print("he address of s is: \(s.address())") 
} 
func testPassingByReference(s: inout String) { 
    print("he address of s is: \(s.address())") 
} 

testPassingByValue(s: str) 

0x7fd6c9e05270

testPassingByReference(s: &str) 

0x7fd6c9e7caf0

私は値によって引数を渡すときにアドレスが異なる理由は理解していますが、引数をinoutパラメータとして渡すときに期待するものではありません。

アップルの開発者向けウェブサイトは、我々は関数に渡すオブジェクトのコピーを避けるためにどのような方法があり、

In Swift, Array, String, and Dictionary are all value types.

がそこで質問があると述べている(私は非常に大きな配列を持つことができますか辞書)またはスウィフトは私たちにそのようなことを許可していないのですか?

答えて

2

配列と文字列をコピーするのは、変更しない限り安く(ほとんど無料です)。 Swiftはstdlibでこれらのコレクションのコピーオンライトを実装しています。これは言語レベルの機能ではありません。実際には配列や文字列(と他の型)に対して明示的に実装されています。したがって、すべて同じバッキングストレージを共有する大規模なアレイの多数のコピーを持つことができます。

inoutは「参考として」と同じものではありません。文字通り「イン・アウト」です。値は関数の先頭でコピーされ、最後に元の位置にコピーされます。

Swiftのアプローチは一般的な用途では実用的になりがちですが、SwiftはC++のように強力なパフォーマンスの約束をしません。これは、Swiftがデータ構造の選択に制限されていないため、SwiftはC++より高速である場合があるということです。)一般的なルールとして、任意スウィフトコード。最悪の場合のパフォーマンスについては簡単に理由を説明することはできますが(コピーが常に発生すると仮定します)、コピーを避けることが確実にわかるのは難しいです。

+0

興味深いことに、「すべて同じバッキングストレージを共有している」ということを実際に見る方法はありますか?アドレスを印刷するか、デバッガのどこかで表示したいのですか? – Alex

+0

内部の '_buffer'プロパティを突き止めることができます。 'array.withUnsafeBytes'を見て、そこから出てくるポインタを確認することもできます。内部ストレージへのポインタです。しかし、それがどのように動作し、コピーを作成するかについての約束はたくさんありません。あなたはソースコードを見て回ってみることができます:https://github.com/apple/swift –

+0

答えをありがとう。 – Alex

2

inoutパラメータは、関数の入力パラメータとして使用された変数を変更しますが、のように正確には動作しません。他の言語で表示されます。 Swiftでの動作は、コピーインコピーアウトまたは値による呼び出し結果と呼ばれます。これは、inoutパラメータを使用すると、関数呼び出し時にその値がコピーされ、関数内で変数のローカルコピーが変更されることを意味します。関数が復帰した時点で、パラメータの元のメモリ位置の値がinoutの値を変更されたコピー値で上書きします。

変数のアドレスをファンクションに印刷しているため、実際にコピーした値の場所が表示されています。関数が返された後で印刷を試してください。変更した値で元の場所を印刷していることがわかります。

詳細については、In-Out parametersのマニュアルを参照してください。

関連する問題