1. How to use Variadic parameters in Swift

可变参数使向函数传递零个或多个特定类型的值成为可能。对于经常使用一个元素的方法来说,它是一种干净的替代方法,并且您不希望为实现级别为单个值的创建组件数组。

可变参数的伟大之处在于Swift处理将单个值转换为值的集合。当Swift处理转换时,我们可以保持我们的api更容易读懂和干净。让我们看看它是如何工作的。

1.1. What is a Variadic Parameter?

可变参数是用值类型后跟3个点来定义的,例如:

mutating func add(_ newContent: Content...) {
    content.append(contentsOf: newContent)
}

这个add(_:)方法现在只能同时接受一个或多个值:

struct Content {
     let title: String
}

struct Bucket {
    private(set) var content: [Content] = []
    
    mutating func add(_ newContent: Content...) {
        content.append(contentsOf: newContent)
    }
}

var bucket = Bucket()

/// Add only a single content item:
bucket.add(Content(title: "Blog post 1"))

/// Add multiple items:
bucket.add(Content(title: "Blog post 2"), Content(title: "Blog post 3")) 

自从Swift 5.4随Xcode 12.5一起发布以来,我们现在也可以在方法定义中定义多个可变参数:

mutating func add(_ newContent: Content..., newUsers: User...) {
    content.append(contentsOf: newContent)
    users.append(contentsOf: newUsers)
} 

如果您希望多个参数能够灵活地接收零个或多个值,那么这非常好。

1.2. Understanding the limitations of Variadic Parameters

可变参数在许多情况下是非常适合的,但也不是正确的解决方案。这是由于它的局限性,知道它对决定使用可变参数是否有用很重要。

1.2.1. A Variadic Argument can also be empty

如果参数被隐式定义为一个数组,那么理解传入一个空数组是合乎逻辑的

struct Bucket {
    private(set) var content: [Content] = []
    
    mutating func add(_ newContent: [Content]) {
        content.append(contentsOf: newContent)
    }
}

var bucket = Bucket()
bucket.add([]) 

可变参数的基础值也是一个数组,这意味着我们可以做完全相同的事情:

struct Bucket {
    private(set) var content: [Content] = []
    
    mutating func add(_ newContent: Content...) {
        content.append(contentsOf: newContent)
    }
}

var bucket = Bucket()
bucket.add()

在大多数情况下,这应该不是问题,因为您的方法的实现需要处理元素数组。但是,您可能有一些内置的日志记录,在这些情况下也可以执行。只是要注意!

1.2.2. Passing an array of values as a variadic argument doesn’t work

虽然在2019年有一个提议让这个工作,但仍然不可能将数组作为可变参数传入:

虽然它可能期望这工作,你会遇到以下错误:

不能传递类型“[内容]”的数组作为类型“内容”的可变参数

目前解决这个问题的唯一方法是添加另一个重载方法来接受内容数组:

struct Bucket {
    private(set) var content: [Content] = []
    private(set) var users: [User] = []
    
    mutating func add(_ newContent: Content..., newUsers: User...) {
        content.append(contentsOf: newContent)
        users.append(contentsOf: newUsers)
    }
    
    mutating func add(_ newContent: [Content]) {
        content.append(contentsOf: newContent)
    }
} 

或者通过创建一个协议使单个项目和多个项目相等。

1.3. Conclusion

当一个方法经常接收一个或多个值时,可变参数是在实现级别上保持代码整洁的好方法。然而,可变参数有一些限制,在决定在您的场景中使用它们之前需要考虑这些限制。