web-dev-qa-db-ja.com

Swiftオプションの入出力パラメータとnil

Swiftの関数にOptionalinoutパラメーターを指定することは可能ですか?私はこれをやろうとしています:

func testFunc( inout optionalParam: MyClass? ) {
    if optionalParam {
        ...
    }
}

...しかし、それを呼び出してnilを渡そうとすると、奇妙なコンパイルエラーが発生します。

Type 'inout MyClass?' does not conform to protocol 'NilLiteralConvertible'

クラスがすでにオプションとして宣言されているのに、なぜクラスが特別なプロトコルに準拠する必要があるのか​​わかりません。

19
devios1

関数は参照を期待しているがnilを渡したため、コンパイルされません。問題はオプションとは何の関係もありません。

inoutを使用してパラメーターを宣言することは、関数本体内でパラメーターに値を割り当てることを意味します。 nilに値を割り当てるにはどうすればよいですか?

あなたはそれを次のように呼ぶ必要があります

var a : MyClass? = nil
testFunc(&a) // value of a can be changed inside the function

C++を知っている場合、これはオプションのないコードのC++バージョンです。

struct MyClass {};    
void testFunc(MyClass &p) {}
int main () { testFunc(nullptr); }

そしてあなたはこのエラーメッセージを持っています

main.cpp:6:6: note: candidate function not viable: no known conversion from 'nullptr_t' to 'MyClass &' for 1st argument

これは、あなたが得たものと同等です(しかし理解しやすい)

26
Bryan Chen

実際、@ devios1に必要なのは「オプションのポインタ」です。しかし、MyClassはどうですか? 「オプションへのポインタ」を意味します。以下はSwift 4で動作するはずです

class MyClass {
    // func foo() {}
}

func testFunc(_ optionalParam: UnsafeMutablePointer<MyClass>? ) {
    if let optionalParam = optionalParam {
        // optionalParam.pointee.foo()
        // optionalParam.pointee = MyClass()
    }
}

testFunc(nil)

var myClass = MyClass()
testFunc(&myClass)
2

正確な ドキュメントからのパス は次のとおりです。

変数は、入出力パラメーターの引数としてのみ渡すことができます。定数とリテラルは変更できないため、定数またはリテラル値を引数として渡すことはできません。アンパーサンド(&)を変数として引数に入力パラメーターとして渡す場合、変数名の直前に配置して、関数で変更できることを示します。

ただし、@ gnasherのコメントに従って(編集済み)、クラスをinout(別名参照)として渡す必要があるのは、インスタンスを別のインスタンスに置き換えたり、インスタンスを置き換えたりするだけでなく、オリジナルが変更されました。これをカバーするドキュメンテーションの節は次のとおりです:

入出力パラメーター

上記の変数パラメーターは、関数内でのみ変更できます。関数でパラメーターの値を変更し、関数呼び出しの終了後もそれらの変更を保持する場合は、代わりにそのパラメーターを入出力パラメーターとして定義します。

Varとinoutの使用法をカバーする3つのテストを次に示します。

class Bar : Printable {
    var value = 1

    init(_ value:Int) { self.value = value }
    var description:String { return "Bar is: \(value)" }
}

let bar = Bar(1)
func changeBarWithoutInoutSinceBarIsAClassYaySwift(b:Bar) { b.value = 2 }
changeBarWithoutInoutSinceBarIsAClassYaySwift(bar)
println("after: \(bar)") // 2

var bar2 = Bar(0)
func tryToReplaceLocalBarWithoutInout(var b:Bar) { b = Bar(99) }
tryToReplaceLocalBarWithoutInout(bar2)
println("after: \(bar2)") // 0

var bar3 = Bar(0)
func replaceClassInstanceViaInout(inout b:Bar) { b = Bar(99) }
replaceClassInstanceViaInout(&bar3)
println("after: \(bar3)") // 99
2
Chris Conover