'var'パラメータは非推奨であり、Swift 3で削除されます


120

Xcodeを7.3に更新するだけで、次の警告が表示されます。

'var'パラメータは非推奨であり、Swift 3で削除されます

この関数で変数を使用する必要があるときにこれを修正する方法:

public func getQuestionList(var language: String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

6
いかがですかpublic func getQuestionList(inout language: String) -> NSArray
TotoroTotoro 2016年

2
いいえ、これは適切な代替品ではありません。OPはおそらくgetQuestion副作用を望まないでしょう。
BallpointBen 2016年

5
正直なところ、なぜこれを削除することさえ検討するのかわかりません。これは、素晴らしかった機能の1つでした。
Danny Bravo

私自身はそれを使用したことがなく、大騒ぎを理解していません。
Mike Taverne、2016

@MikeTaverne(遅延応答)次の関数について考えてみますfunc foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }。これは、var paramsなしでは不可能です。関数内で別個の変数を作成して値をコピーするか、パラメーターをinoutとしてマークする必要があります。前者は遅く、後者は未定義の動作を引き起こします。多くのアルゴリズムはこのような再帰を使用します。
ケビン2018年

回答:


82

新しい変数に割り当てようとしましたか

public func getQuestionList(language: String) -> NSArray {
    var lang = language
    if self.data.count > 0 {
        if (lang.isEmpty) {
            lang = "NL"
        }
        return self.data.objectForKey("questionList" + lang) as! NSArray
    }

    return NSArray()
}

11
OPが欲しかったとは思いません
ブリムストーン2016年

6
OPの質問は@garanaと同じように理解できただろう。OPは質問でinoutを使用していません。既存の変数をローカルで変更するだけです。
Eric Aya

11
実際、これは正しい解決策です。この変更を提案したSwiftの進化の問題をご覧ください:github.com/apple/swift-evolution/blob/master/proposals/…–
Scott Thompson

8
@TimVermeulen誰もが進歩的な言語を使用したいと考えています。Appleは、毎月構文を変更するのではなく、さまざまな方法で言語を開発できます。ご存知のように、Appleが原因で、大量のオンラインドキュメントとコードスニペットが期限切れになったり、古くなったりしています。そのため、開発者はこのサイトにアクセスして、多くの愚かな質問に繰り返し助けを求める必要があります。Appleがより多くの開発者に上手になりたい場合、構文は最初からしっかりしている必要があります。
TomSawyer 2016年

25
別の変数名を導入したくない場合は、var language = languageを使用してください(そもそもvarパラメータの主な利点はimoでした)
Harris

102

関数パラメーターからのVarの削除についての議論は、GitHubのこの送信内に完全に文書化されています:Varパラメーターの削除

そのドキュメントでは、人々がしばしばvarパラメーターとinoutパラメーターを混同していることがわかります。varパラメータは、単にパラメータを用いているが、関数のコンテキスト内で変更可能であることを意味しますinoutパラメータリターンの点におけるパラメータの値は、関数の呼び出し元のコンテキストに出てコピーされます。

この問題を解決する正しい方法はvar、パラメーターから削除してローカルvar変数を導入することです。ルーチンの先頭で、パラメーターの値をその変数にコピーします。


44
私はこの変更をまったく理解していませんが、可変のローカル変数を作成するために別の行を記述する必要があるのは、単にパラメーターを変数として定義するよりも優れているのですか?
ロスバービッシュ2016年

ローカル変数を実装する必要があった状況を取り上げているため、この変更は適切ですが、簡単な方法を採用して、入力パラメーターをvarにするというSwiftの提案(古い)を受け入れたため、そうしませんでした
dawid

1
私はこれについて@RossBarbishと一緒にいます。だから...これは、怠惰な開発者がinoutパラメータとvarパラメータを区別できないために削除されていますか?Pfff ...
ダニーブラボー

1
これはひどく不必要に見えます...彼らは両方のオプションを保持するべきでした。
オスカーゴメス

1
おそらく、swiftは、とにかく舞台裏でパラメータの上部にローカル変数を宣言していました。これを手動で行う必要があります。性能に変化はありませんでしたが、初心者がシンプルなコンセプトで作業できるように利便性を失いました。
mogelbuster

62

関数の先頭に次の1行を追加するだけです。

var language = language

次のように、コードの残りの部分は変更されないままにすることができます。

public func getQuestionList(language: String) -> NSArray {
    var language = language
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

5
断然ベストな答えです。1行だけ変更する必要があります。
BallpointBen 2016年

しかし、とても不自然に見えます@James
asyncwait

1
同じ名前を付けているので、これが最良の答えだと思います。他の一般的な言語が行う方法と同様です。
eonist

1
@RiverSatyaパラメータを直接使用しないのはなぜですか?
Declan McKenna

1
本当に素晴らしい提案です。この方法でSwiftifyに実装します:)
Crulex

13

多くの人がinoutパラメータを提案していますが、それは実際には設計されたものではありません。また、let定数や文字列リテラルを使用して関数を呼び出すことはできません。関数のシグネチャにデフォルト値を追加しないのはなぜですか?

public func getQuestionList(language language: String = "NL") -> NSArray {
    if data.count > 0 {
        return data.objectForKey("questionList" + language) as! NSArray
    } else {
        return NSArray()
    }
}

getQuestionListデフォルトの言語が必要な場合に備えて、空の文字列で呼び出さないようにしてください。パラメータは省略してください。

let list = getQuestionList() // uses the default "NL" language

3
また、OPが最初はそれを使用していなかったのに、なぜみんながinoutソリューションに飛びついたのか理解できません...
Eric Aya

1
彼らは、varとinoutが同じことをすると仮定していました。
ryantxr 2016年

2

スウィフト4

public func getQuestionList(language: inout String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

getQuestionList(language: &someString)

私が経験したように(配列を含むより複雑なセットアップで)、メソッド内に新しいプロパティを作成し、そのプロパティを変更すると、常に機能するとは限りません。言うまでもなく、この構文が作成されたのは、単にinoutパラメーターと&引数に追加するのではなく、メソッドを雑然としているためです。



0

@Harrisと@garandaの答えが最善のアプローチだと思います。

とにかくあなたのケースでは、変数の必要はありません、あなたは行うことができます:

public func getQuestionList(language: String) -> NSArray {
    if self.data.count > 0 {
        return self.data.objectForKey("questionList" + (language.isEmpty ? "NL" : language)) as! NSArray
    }
    return NSArray()
}

0

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html

入出力パラメーター

関数パラメーターは、デフォルトでは定数です。関数の本体内から関数パラメーターの値を変更しようとすると、コンパイル時エラーが発生します。つまり、誤ってパラメーターの値を変更することはできません。関数でパラメーターの値を変更し、関数呼び出しの終了後もそれらの変更を保持する場合は、代わりにそのパラメーターを入出力パラメーターとして定義します。

inoutキーワードをパラメーターの型の直前に置くことにより、in-outパラメーターを記述します。入出力パラメーターには、関数に渡される値があり、関数によって変更され、元の値を置き換えるために関数から戻されます。入出力パラメーターの動作と関連するコンパイラーの最適化の詳細については、入出力パラメーターを参照してください。

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

注意

入出力パラメーターにデフォルト値を設定することはできません。可変パラメーターは、入出力としてマークすることはできません。

次に、aとbと呼ばれる2つの入出力整数パラメータを持つswapTwoInts( :) という関数の例を示します。

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

swapTwoInts( :)関数は、単にbの値をaに、aの値をbにスワップします。この関数は、aの値をtemporaryAと呼ばれる一時定数に格納し、bの値をaに割り当て、temporalAをbに割り当てることによって、このスワップを実行します。

Int型の2つの変数を使用してswapTwoInts( :)関数を呼び出すと、それらの値を交換できます。someIntとanotherIntの名前は、swapTwoInts( :)関数に渡されるときに、アンパサンドが前に付けられることに注意してください。

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"

上記の例は、someIntとanotherIntの元の値がswapTwoInts(関数の外部で定義されていたとしても :)関数ています。

注意

入出力パラメーターは、関数から値を返すことと同じではありません。上記のswapTwoIntsの例では、戻り値の型や値を定義していませんが、someIntとanotherIntの値を変更しています。入出力パラメーターは、関数がその関数本体のスコープ外で効果を持つための代替方法です。


0

ここに別のアイデアがあります。私の使用例は、追加する文字列配列を渡すことでした。そのため、配列は変更可能に渡される必要があります。私もこれについてクラスで状態を持ちたくありませんでした。だから私は配列を保持し、それを渡すクラスを作りました。ユースケースによっては、その1つの変数のみを保持するクラスがあるのはばかげているように見えるかもしれません。

private class StringBuilder {
    var buffer: [String] = []

    func append(_ str: String) {
        buffer.append(str)
    }

    func toString() -> String {
        return buffer.joined()
    }
}

私は使用しappendjoinedは配列でメソッドているため、コードへのその他の変更を最小限に抑えて型を変更するのは簡単でした。

いくつかの使用例:

private func writeMap(map: LevelMap, url: URL) -> Bool {
    let buffer = StringBuilder()

    if !writeHeader(map: map, buffer: buffer) {
        return false
    }
    if !writeFloors(map: map, buffer: buffer) {
        return false
    }

    let content = buffer.toString()
    do {
        try content.write(to: url, atomically: true, encoding: .utf8)
        return true
    } catch {}
    return false
}

private func writeHeader(map: LevelMap, buffer: StringBuilder) -> Bool {
    buffer.append("something here ...\n")
    return true
}

私の答えは、発信者から見た元の値を変更したい場合です。ローカルで値を再割り当てできるようにしたいが、それが呼び出し元に影響を与えないようにしたい場合は、上記の他の回答で対処できます。
webjprgm 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.