在Swift中将数组传递给具有可变数量args的函数


151

Swift编程语言中,它说:

函数也可以采用可变数量的参数,将它们收集到一个数组中。

  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年

Answers:



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似乎能够用相同的函数名称分隔两个调用之间的差异。

另外,如果Apple按照@manojid的答案所建议的那样更新语言,则只需要更新这些功能即可。否则,您将必须进行大量重命名。


谢谢,我喜欢解决方法。我仍然会授予manojlds“正确”的答案,以查找指向该功能尚不可用的官方确认的链接。我希望你明白。
Ole Begemann 2014年

您可能正在遵循《指南》,您的函数sumOf(numbers [Int])-> Int实际上正在计算平均值
gfelisberto 2015年

18

您可以强制转换函数:

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

大!这也适用于多个(命名)参数。例如:func sumOf(foo numbers: Int..., bar: Bool) -> Int {};requirestypealias Function = (foo: [Int], bar: Bool) -> Int;
ThomasR

大!救我一命。
JerryZhou

我如何使用AnyObject ...做类似的事情? stackoverflow.com/questions/42016358/… 谢谢。
周杰伦'17

这是一个非常糟糕的主意。绝对零保证这将起作用。
idmean

1
@MattMc当然。据我所知,没有什么可以让您简单地将一个可调用类型转换为另一个可调用类型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的答案更适合您的问题,但我想出了另一种解决方法。我确实也喜欢Logan更好。

就我而言,我只想传递一个数组:

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

我做到了(包装+身份映射):

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.