Swiftで可変数の引数を持つ関数に配列を渡す


151

スウィフトプログラミング言語、それは言います:

関数は可変数の引数を取り、それらを配列に収集することもできます。

  func sumOf(numbers: Int...) -> Int {
      ...
  }

このような関数をコンマ区切りの数値リスト( `sumOf(1、2、3、4))で呼び出すと、関数内で配列として使用できるようになります。

質問:この関数に渡したい数値の配列がすでにある場合はどうなりますか?

let numbers = [1, 2, 3, 4]
sumOf(numbers)

これは、「指定された引数を受け入れる '__conversion'のオーバーロードを見つけられませんでした」というコンパイラエラーで失敗します。既存の配列を可変個関数に渡すことができる要素のリストに変換する方法はありますか?


1
代わりに整数配列を取るように関数を構成しないのはなぜですか?
Mick MacCallum、2014年

26
もちろん、私は関数の作成者ではない可能性があり、関数を変更できない(または変更したい)場合があります。
Ole Begemann、2014年

回答:


96

開発者によって確認されたように、スプラッティングはまだ言語ではありません。現時点での回避策は、オーバーロードを使用するか、オーバーロードを追加できない場合は待機することです。


3
スプラッティングはその言語でまだですか?電話をかけようとしていますsumOf(...numbers)
Noitidart、

とても残念!自分のログコールをprint
マークA.ドノホー

65

これが私が見つけた回避策です。それがあなたの望むものではないことは知っていますが、動作しているようです。

ステップ1:可変個引数の代わりに配列を使用して、必要な関数を宣言します。

func sumOf(numbers: [Int]) -> Int {
    var total = 0
    for i in numbers {
        total += i
    }
    return total
}

ステップ2:可変関数内からこれを呼び出す:

func sumOf(numbers: Int...) -> Int {
    return sumOf(numbers)
}

ステップ3:どちらかの方法で呼び出す:

var variadicSum = sumOf(1, 2, 3, 4, 5)
var arraySum = sumOf([1, 2, 3, 4, 5])

奇妙に思えますが、私のテストでは機能しています。これが誰かに予期しない問題を引き起こすかどうかを知らせてください。Swiftは、同じ関数名を持つ2つの呼び出しの違いを区別できるようです。

また、この方法では、@ manojidの回答が示唆するようにAppleが言語を更新した場合、これらの関数を更新するだけで済みます。それ以外の場合は、何度も変更して、名前を変更する必要があります。


おかげで、私は回避策が好きです。私はまだ、機能がまだ利用できないという公式の確認へのリンクを見つけるためのmanojldsへの「正しい」答えを与えます。ご理解頂けるとありがたいです。
Ole Begemann、2014年

あなたはおそらくガイドとfunc sumOf(numbers:[Int])-> Intが実際に平均を計算しています
gfelisberto

18

関数をキャストできます:

typealias Function = [Int] -> Int
let sumOfArray = unsafeBitCast(sumOf, Function.self)
sumOfArray([1, 2, 3])

すごい!これは複数の(名前付き)パラメータでも機能します。例:func sumOf(foo numbers: Int..., bar: Bool) -> Int {};必要typealias Function = (foo: [Int], bar: Bool) -> Int;
ThomasR

すごい!私の命を助けて。
JerryZhou 2017年

AnyObject ...で同様のことをするにはどうすればよいですか? stackoverflow.com/questions/42016358/… ありがとう。
JerryZhou 2017

これは非常に悪い考えです。これが機能するという保証はまったくありません。
idmean

1
@MattMcもちろん。私が知る限り、を使用して1つの呼び出し可能な型を別の呼び出し可能な型に単純にキャストできるものはありませんunsafeBitCast。これは今日は機能するかもしれませんが、リファレンスがそうでない限り、コンパイラの次のバージョンは文字通りここで何でも自由にできます(コンパイラエラー/クラッシュ/ランダムに実行するコード...)。unsafeBitCastの深刻な警告をご覧ください
idmean

15

次のようにヘルパー関数を使用できます。

func sumOf (numbers : [Int])  -> Int { return numbers.reduce(0, combine: +) }
func sumOf (numbers : Int...) -> Int { return sumOf (numbers) }

12
アレイのバージョンがある場合。質問の前提は、元の機能が使用されInt...、(簡単に)変更できないということですか?

2
@delnan:正解です。可変引数がとにかく配列に変換されることを考えると、可変関数に配列を渡す方法があるはずだと私には思われます。
Ole Begemann、2014年

1
Schemeなどの関数で可変数の引数を受け入れる言語には、applyプロシージャがあります。「スプラッティング」と呼ぶ人もいます。
GoZoner 2014年

1
sumArrayここで何が参照されていますか?
Rob

2

この回答があなたの正確な質問に答えていないことは知っていますが、注目に値します。私もSwiftを使い始めていて、すぐに同じような質問に遭遇しました。あなたの質問にはManojldsの回答の方が適しています。私もたまたまローガンのほうが好きだ。

私の場合、配列を渡したかっただけです:

func sumOf(numbers: Array<Int>) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}

var someNums = [8,7,2,9,12]
sumOf(someNums)
sumOf([10, 15, 20])

誰かが私のように考えている場合に備えて、共有したかっただけです。ほとんどの場合、私はこのように配列を渡すことを望みますが、「迅速に」とはまだ思っていません。:)


1

私はこれを行いました(ラッパー+ IDマッピング):

func addBarButtonItems(types: REWEBarButtonItemType...) {
    addBarButtonItems(types: types.map { $0 })
}

func addBarButtonItems(types: [REWEBarButtonItemType]) {
    // actual implementation
}

0

スウィフト5

これは、@dynamicCallable過負荷を回避できる機能を備えたアプローチですが、呼び出しをunsafeBitCast指定structする必要があります。

@dynamicCallable
struct SumOf {
    func dynamicallyCall(withArguments args: [Int]) -> Int {
        return args.reduce(0, +)
    }
}

let sum = SumOf()

// Use a dynamic method call.
sum(1, 2, 3) // 6

// Call the underlying method directly.
sum.dynamicallyCall(withArguments: [1, 2, 3]) // 6
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.