Truyền một mảng cho một hàm với số lượng đối số biến đổi trong Swift


151

Trong Ngôn ngữ lập trình Swift , nó nói:

Các hàm cũng có thể lấy một số lượng đối số khác nhau, thu thập chúng thành một mảng.

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

Khi tôi gọi một hàm như vậy với danh sách các số được phân tách bằng dấu phẩy (`sumOf (1, 2, 3, 4), chúng được cung cấp dưới dạng một mảng bên trong hàm.

Câu hỏi: nếu tôi đã có một mảng các số mà tôi muốn chuyển đến hàm này thì sao?

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

Điều này không thành công với lỗi trình biên dịch, không thể tìm thấy quá tải cho '__conversion' chấp nhận các đối số được cung cấp. Có cách nào để biến một mảng hiện có thành một danh sách các phần tử mà tôi có thể chuyển đến một hàm matrixdic không?


1
Tại sao không chỉ cấu hình hàm để lấy một mảng số nguyên thay thế?
Mick MacCallum

26
Chắc chắn, nhưng tôi có thể không phải là tác giả của chức năng và có thể không (hoặc muốn) thay đổi nó.
Ole Begemann

Câu trả lời:


96

Spleting chưa có trong ngôn ngữ , như được xác nhận bởi các nhà phát triển. Giải pháp cho bây giờ là sử dụng quá tải hoặc chờ nếu bạn không thể thêm quá tải.


3
Là Spleting trong ngôn ngữ chưa? Tôi đang cố gọisumOf(...numbers)
Noitidart

Thật đáng thất vọng! Tôi nhấn vào điều này ngay cả với một cái gì đó đơn giản như cố gắng ủy thác các cuộc gọi nhật ký của riêng tôi xuống print!
Đánh dấu A. Donohoe

65

Đây là một công việc xung quanh mà tôi tìm thấy. Tôi biết đó không phải là chính xác những gì bạn muốn, nhưng nó dường như đang hoạt động.

Bước 1: Khai báo hàm bạn muốn với một mảng thay vì các đối số biến đổi:

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

Bước 2: Gọi đây từ trong hàm matrixdic của bạn:

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

Bước 3: Gọi một trong hai cách:

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

Có vẻ lạ, nhưng nó đang làm việc trong các thử nghiệm của tôi. Hãy cho tôi biết nếu điều này gây ra vấn đề không lường trước cho bất cứ ai. Swift dường như có thể phân tách sự khác biệt giữa hai cuộc gọi có cùng tên chức năng.

Ngoài ra, với phương pháp này nếu Apple cập nhật ngôn ngữ như câu trả lời của @ manojid, bạn sẽ chỉ cần cập nhật các chức năng này. Nếu không, bạn sẽ phải trải qua và thực hiện nhiều đổi tên.


Cảm ơn, tôi thích cách giải quyết. Tôi vẫn sẽ trao câu trả lời "chính xác" cho manojlds vì đã tìm thấy liên kết đến xác nhận chính thức rằng tính năng này chưa khả dụng. Tôi hy vọng bạn hiểu.
Ole Begemann

Bạn có thể đang theo Hướng dẫn và func sumOf của bạn (số: [Int]) -> Int thực sự đang tính trung bình
gfelisberto

18

Bạn có thể truyền chức năng:

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

Tuyệt quá! Điều này cũng hoạt động với nhiều tham số (được đặt tên); ví dụ: func sumOf(foo numbers: Int..., bar: Bool) -> Int {};yêu cầutypealias Function = (foo: [Int], bar: Bool) -> Int;
ThomasR

Tuyệt quá! cứu mạng tôi
JerryZhou

Làm cách nào tôi có thể làm những điều tương tự với AnyObject ...? stackoverflow.com/questions/42016353/ cảm ơn.
JerryZhou

Đây là một ý kiến ​​tồi. Hoàn toàn không có đảm bảo rằng điều này sẽ làm việc.
idmean

1
@MattMc Chắc chắn. Theo như tôi có thể nói, không có gì cho phép bạn chỉ cần sử dụng một loại có thể gọi được cho loại khác bằng cách sử dụng unsafeBitCast. Điều này có thể hoạt động ngày hôm nay, nhưng trừ khi một tài liệu tham khảo nói như vậy, phiên bản tiếp theo của trình biên dịch có thể tự do làm bất cứ điều gì ở đây (lỗi trình biên dịch / sự cố / mã thực thi ngẫu nhiên ...). Hãy xem cảnh báo nghiêm túc trên unsafeBitCast .
idmean

15

Bạn có thể sử dụng chức năng trợ giúp như vậy:

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

12
Với điều kiện là có một phiên bản cho mảng. Tôi nghĩ tiền đề của câu hỏi là chức năng ban đầu mất Int...và không thể (dễ dàng) thay đổi?

2
@del Nam: Đúng. Dường như với tôi rằng nên có cách chuyển một mảng thành một hàm matrixdic, với điều kiện là các đối số matrixdic được chuyển thành một mảng.
Ole Begemann

1
Các ngôn ngữ chấp nhận số lượng đối số khác nhau trong các hàm, như Scheme, có một applythủ tục. Tôi tập hợp một số người gọi đó là 'bắn tung tóe'.
GoZoner

1
Những gì được sumArraytham khảo ở đây?
Rob

2

Tôi biết câu trả lời này không trả lời chính xác câu hỏi của bạn, nhưng tôi cảm thấy đáng chú ý. Tôi cũng đã bắt đầu chơi với Swift và ngay lập tức gặp phải một câu hỏi tương tự. Câu trả lời của Manojlds tốt hơn cho câu hỏi của bạn, tôi đồng ý, nhưng một lần nữa, một cách giải quyết khác mà tôi đã đưa ra. Tôi cũng thích Logan hơn.

Trong trường hợp của tôi, tôi chỉ muốn vượt qua một mảng:

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])

Chỉ muốn chia sẻ, trong trường hợp bất cứ ai khác cũng nghĩ như tôi. Hầu hết thời gian tôi muốn vượt qua mảng như thế này, nhưng tôi chưa nghĩ là "Nhanh chóng". :)


1

Tôi đã làm điều này (Wrapper + Bản đồ nhận dạng):

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

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

0

Swift 5

Đây là một cách tiếp cận với @dynamicCallabletính năng cho phép tránh quá tải hoặc unsafeBitCastnhưng bạn nên thực hiện một structcuộc gọi cụ thể :

@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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.