How to forward functions with variadic parameters?

白昼怎懂夜的黑 提交于 2019-12-17 13:44:13

问题


In Swift, how do you convert an Array to a Tuple?

The issue came up because I am trying to call a function that takes a variable number of arguments inside a function that takes a variable number of arguments.

// Function 1
func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}
// Example Usage
sumOf(2, 5, 1)

// Function 2
func averageOf(numbers: Int...) -> Int {
    return sumOf(numbers) / numbers.count
}

This averageOf implementation seemed reasonable to me, but it does not compile. It gives the following error when you try to call sumOf(numbers):

Could not find an overload for '__converstion' that accepts the supplied arguments

Inside averageOf, numbers has the type Int[]. I believe sumOf is expecting a Tuple rather than an Array.

Thus, in Swift, how do you convert an Array to a Tuple?


回答1:


This has nothing to do with tuples. Anyway, it isn't possible to convert from an array to a tuple in the general case, as the arrays can have any length, and the arity of a tuple must be known at compile time.

However, you can solve your problem by providing overloads:

// This function does the actual work
func sumOf(_ numbers: [Int]) -> Int {
    return numbers.reduce(0, +) // functional style with reduce
}

// This overload allows the variadic notation and
// forwards its args to the function above
func sumOf(_ numbers: Int...) -> Int {
    return sumOf(numbers)
}

sumOf(2, 5, 1)

func averageOf(_ numbers: Int...) -> Int {
    // This calls the first function directly
    return sumOf(numbers) / numbers.count
}

averageOf(2, 5, 1)

Maybe there is a better way (e.g., Scala uses a special type ascription to avoid needing the overload; you could write in Scala sumOf(numbers: _*) from within averageOf without defining two functions), but I haven't found it in the docs.




回答2:


As of Swift 4.1 (in Xcode 9.2), there is no need to overload with sumOf(_ numbers: Int...), the function that forward variadic parameter(s) will IMPLICITLY change it to a single parameter of array of individual parameter(s). E.g. the following code will work without the overloading:

// This function does the actual work
func sumOf(_ numbers: [Int]) -> Int {
    return numbers.reduce(0, +) // functional style with reduce
}

func averageOf(_ numbers: Int...) -> Int {
    // This calls the first function directly
    return sumOf(numbers) / numbers.count
}

print(averageOf(2, 5, 1))

Don't know whether this is a bug of the compiler or not :)




回答3:


I realize this is an older post, but this came up rather high in the search results and I found a working solution.

You can write the sumOf function to accept an array of integers as the number parameter and overload the sumOf function to accept a variadic input for the numbers parameter which will be passed to the first version as an array. This way the averageOf function can pass its variadic input as array to sumOf.

This does not seem very ideal because you need to overload each function that works like this, but it will work in the way you wanted.

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

// Function 1
func sumOf(numbers: Int...) -> Int {
    return sumOf(numbers: numbers)
}
// Example Usage
sumOf(2, 5, 1)

// Function 2
func averageOf(numbers: Int...) -> Int {
    return sumOf(numbers: numbers) / numbers.count
}



回答4:


I don't think he needs to use .reduce. Instead just change the parameter definition in his sumOf function. Instead of:

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

write:

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


来源:https://stackoverflow.com/questions/24046142/how-to-forward-functions-with-variadic-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!