可变参数究竟是如何工作的?



我是 Swift 新手,在理解可变参数到底是什么以及为什么它有用时遇到了一些麻烦。我目前正在关注在线 Swift 5.3 指南,这是为此类参数给出的示例。

func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers

显然,名为numbers的可变参数具有一种Double...,这允许它在函数的主体中用作常量数组。为什么该函数返回Double(numbers.count)而不仅仅是numbers.count?与其创建一个可变参数,为什么不创建一个参数来接收像这样的函数之外的数组呢?

func addition(numbers : [Int]) -> Int
{
var total : Int = 0
for number in numbers
{
total += number
}
return total
}
let totalBruhs : [Int] = [4, 5, 6, 7, 8, 69]
addition(numbers: totalBruhs)

另外,为什么每个函数只能有一个可变参数?

可变参数需要(嗯,不需要,但很好)存在于Swift 中,因为它们存在于 C 中,而 Swift 中的许多东西都存在于 C 中。在 C 语言中,创建任意长度的快速数组并不像在 Swift 中那么简单。

如果你从头开始构建 Swift,没有向后兼容 C,那么也许它们会被添加,也许不会。 (虽然我敢打赌是的,只是因为很多 Swift 开发人员习惯了它们存在的语言。但话又说回来,像Zig这样的语言故意去掉了可变参数,所以我不知道。Zig 还演示了你不需要可变参数来桥接到 C,但它仍然很好。@Rob下面的评论值得一读。他可能没有错。此外,他的回答很有见地。

但它们也很方便,因为您不需要添加[...],当只有一个值时,这会更好。特别是,考虑类似print

func print(_ items: Any..., separator: String = " ", terminator: String = "n")

如果没有可变参数,您需要在每个print调用中加入[...],或者您需要重载。可变参数不会改变这里的世界,但它很好。当您考虑过载会产生歧义时,这尤其好。假设您没有可变参数,而是有两个重载:

func print(_ items: [Any]) { ... }
func print(_ item: Any) { print([item]) }

这实际上有点模棱两可,因为 Array 也是一种 Any。所以print([1,2,3])会打印[[1,2,3]].我确信有一些可能的解决方法,但可变参数可以很好地解决这个问题。

只能有一个,因为否则会出现模棱两可的情况。

func f(_ xs: Int..., _ ys: Int...)

在这种情况下,f(1,2,3)该怎么办?什么是xs,什么是ys

您在此处显示的函数不会返回Double(numbers.count)。它将numbers.count转换为双精度,因此可以将其分成另一个双精度。该函数返回total / Double(numbers.count)

与其创建一个可变参数,为什么不创建一个参数来接收函数外部的数组......

我同意你的看法,将数组用于算术函数(如"平均值"、"总和"等)感觉很直观。

话虽如此,在某些情况下,可变参数模式感觉很自然:

  1. 在某些情况下,在编写函数时,在调用点使用数组可能不合逻辑或直观。

    考虑一个应该返回两个值中较大值的max函数。施加一个约束,即调用方必须创建这些值的数组才能返回两个值中较大的一个,这感觉不太对。你真的想允许一个漂亮、简单的语法:

    let result = max(a, b)
    

    但与此同时,作为 API 开发人员,也没有理由将max实现限制为只允许两个参数。也许调用方可能想要使用三个。或更多。作为 API 开发人员,我们为主要用例的自然调用点设计 API,但提供尽可能多的灵活性。因此,可变参数函数参数既非常自然又非常灵活。

    这种模式有很多可能的例子,即任何自然感觉它应该需要两个参数但可能需要更多参数的函数。考虑一个用于两个矩形的union函数,并且您需要边界矩形。同样,您不希望调用方必须为可能是两个矩形的简单并集创建一个数组。

  2. 另一个常见的例子是,您可能有可变数量的参数,但可能不处理数组。典型的例子是printf模式。或者另一种是你与某些SQL数据库交互的地方,并且可能会将值绑定到SQL中的?占位符或类似的东西(以防止SQL注入攻击):

    let sql = "SELECT book_id, isbn FROM books WHERE title = ? AND author = ?"
    let resultSet = db.query(sql, title, author)
    

    同样,在这些情况下,建议调用方必须为此异构值集合创建一个数组在调用点可能感觉不自然。

因此,问题不在于"为什么我要在数组逻辑和直观的情况下使用可变参数?"而是"为什么我要强制使用数组参数?

相关内容

  • 没有找到相关文章

最新更新