Bài tập là viết hàm map()
của riêng tôi qua Collection
(mà không sử dụng bất kỳ hàm nguyên thủy chức năng nào, chẳng hạn như reduce()
). Nó sẽ xử lý một trường hợp như thế này:Tại sao yêu cầu chung là khi tất cả các loại đã được xác định?
func square(_ input: Int) -> Int {
return input * input
}
let result = input.accumulate(square) // [1,2,3] => [1,4,9]
nỗ lực đầu tiên của tôi là:
extension Collection {
func accumulate(_ transform: (Element) -> Element) -> [Element] {
var array: [Element] = []
for element in self {
array.append(transform(element))
}
return array
}
}
này hoạt động tốt trong một sân chơi, nhưng thất bại trong việc xây dựng đối với các bài kiểm tra, đưa ra một lỗi:
Value of type '[Int]' has no member 'accumulate'
giải pháp là để genericize các accumulate
phương pháp:
extension Collection {
func accumulate<T>(_ transform: (Element) -> T) -> [T] {
var array: [T] = []
for element in self {
array.append(transform(element))
}
return array
}
}
Tôi nhận ra rằng phiên bản chung là ít hạn chế (không yêu cầu biến đổi để trả về cùng loại), nhưng cho rằng các phép thử không yêu cầu tính tổng quát này, tại sao trình biên dịch lại?
Out of tò mò tôi đã cố gắng:
extension Collection {
func accumulate<Element>(_ transform: (Element) -> Element) -> [Element] {
var array: [Element] = []
for element in self {
array.append(transform(element))
}
return array
}
}
mà ném build lỗi hấp dẫn: '(Self.Element) -> Element' is not convertible to '(Element) -> Element'
tại báo cáo kết quả append()
.
Vậy trình biên dịch (dĩ nhiên) biết rằng Phần tử đầu tiên là Self.Element, nhưng không xử lý kiểu Element khác như nhau. Tại sao?
UPDATE:
Dựa trên các câu trả lời, dường như từ chối của phiên bản đầu tiên là một lỗi biên dịch, cố định trong XCode 9.2 (Tôi đang trên 9.1).
Nhưng tôi vẫn tự hỏi liệu trong
func accumulate(_ transform: (Element) -> Element) -> [Element]
nó sẽ thấy hai loại (Self.Element
và Element
) hoặc nhận ra rằng họ đang như nhau.
Vì vậy, tôi đã làm bài kiểm tra này:
let arr = [1,2,3]
arr.accumulate {
return String(describing: $0)
}
Chắc chắn, có những lỗi mong đợi: error: cannot convert value of type 'String' to closure result type 'Int'
Vì vậy, câu trả lời đúng là: trình biên dịch sẽ đối xử với tham chiếu đến các phần tử như nhau, như miễn là không có loại chung nào làm quá tải tên.
Nhưng kỳ lạ, mặc dù, điều này thành công:
[1,2,3].accumulate {
return String(describing: $0)
}
PS. Cảm ơn tất cả mọi người vì đầu vào của bạn! Tiền thưởng được tự động trao tặng.
Cả nỗ lực đầu tiên của bạn và lần thử thứ hai biên dịch và chạy mà không gặp sự cố. –