Slice trong Swift là gì?


85

Slice trong Swift là gì và nó khác với một mảng như thế nào?

Từ tài liệu, kiểu chữ ký của chỉ số con (Phạm vi) là:

subscript(Range<Int>) -> Slice<T>

Tại sao không trả lại một cái khác Array<T>hơn là một Slice<T>?

Có vẻ như tôi có thể nối một lát với một mảng:

var list = ["hello", "world"]
var slice: Array<String> = [] + list[0..list.count]

Nhưng điều này dẫn đến lỗi:

không thể tìm thấy quá tải cho 'chỉ số con' chấp nhận các đối số được cung cấp

var list = ["hello", "world"]
var slice: Array<String> = list[0..list.count]

Slice là gì?

Câu trả lời:


97

Slice trỏ vào mảng. Không có ý gì khi tạo mảng khác khi mảng đã tồn tại và lát cắt chỉ có thể mô tả phần mong muốn của nó.

Việc bổ sung gây ra sự ép buộc ngầm, vì vậy nó hoạt động. Để thực hiện nhiệm vụ của mình, bạn cần phải cưỡng chế:

var list = ["hello", "world"]
var slice: Array<String> = Array(list[0..<list.count])

Điều đó có lý. Điều này có được mô tả ở bất kỳ đâu trong tài liệu không?
hjing

2
Đó là một chi tiết triển khai, thực sự. Bạn đã khéo léo thăm dò chiếc vỏ cạnh cho thấy hoạt động của hộp đen ...!
matt

2
thực sự Slice là bản sao của mảng. Sau khi bạn cập nhật mảng ban đầu, lát cắt sẽ không thay đổi. Điều này là do bản chất cấu trúc. Và đối với các lưu ý, giao thức Sliceable không hàm ý sử dụng các loại Slice
Marcin

4
Ngôn ngữ nhanh chóng đã thay đổi và một lát thực sự sử dụng ba dấu ba chấm và không phải là hai developer.apple.com/library/ios/documentation/General/Reference/...
Daniel Galasko

7
Nó sẽ không phá hủy thư từ nếu bạn thêm một chỉnh sửa đơn giản thông báo cho người đọc mới rằng các toán tử phạm vi đã thay đổi?
Daniel Galasko

22

Lưu ý: Câu trả lời này hoàn toàn không hợp lệ kể từ phiên bản Swift beta 3, vì các mảng hiện là kiểu giá trị thực.


@matt là đúng, ở trên - các Slice<T>điểm trong mảng. Điều đó có vẻ trái ngược với cách Swift xử lý tất cả các kiểu dữ liệu khác mà chúng tôi đang làm việc, vì nó có nghĩa là giá trị của lát cắt có thể thay đổi ngay cả khi nó được khai báo là một hằng số:

var arr = ["hello", "world", "goodbye"]    // ["hello", "world", "goodbye"]
let slice = arr[0..2]                      // ["hello", "world"]
arr[0] = "bonjour"
println(slice)                             // ["bonjour", "world"]

Phần tệ nhất là lát cắt hoạt động giống như một mảng. Cho rằng trong Swift, chúng ta có kỳ vọng về tính bất biến, có vẻ như nguy hiểm là các giá trị được chỉ định của lát cắt có thể thay đổi mà không có cảnh báo:

println(slice[1])                          // "world"
arr[1] = "le monde"
println(slice[1])                          // "le monde"

Nhưng nếu mảng cơ bản thay đổi quá nghiêm trọng, chúng sẽ bị mắc kẹt:

arr.removeAtIndex(0)                       // this detaches slice from arr
println(slice)                             // ["bonjour", "le monde"]
arr[0] = "hola"
println(slice)                             // ["bonjour", "le monde"]

6
Trong thực tế, lát làm việc chỉ như mảng, như bạn nói. Mảng Swift có các phần tử có thể thay đổi, ngay cả khi chúng được khai báo là bất biến . Ví dụ, hãy thử let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour". Bạn sẽ thấy nó hoạt động. Với mảng không thể thay đổi, kỳ lạ thay, nó chỉ có kích thước là bất biến, không phải là nội dung. (Xem "mutability của bộ sưu tập" trong Swift Lập trình Ngôn ngữ )
Matt Gibson

1
"Yếu tố Biên Đổi" - Đây là không còn đúng nữa
Alex Brown

14

Tóm lược:

Các câu trả lời ở trên đúng cho đến bản Beta 3 (và có thể thay đổi lại trong các bản phát hành trong tương lai)

Slice bây giờ hoạt động giống như một mảng, nhưng như @matt đã nói ở trên, thực sự là một bản sao nông cho một mảng bên dưới, cho đến khi thực hiện thay đổi. Slices (bây giờ) xem ảnh chụp nhanh các giá trị ban đầu,

Cũng lưu ý rằng cú pháp lát cắt đã thay đổi:

[from..upToButNotIncluding] -> [from..<upToButNotIncluding]

Thí dụ:

var arr = ["hello", "world", "goodbye"] // ["hello", "world", "goodbye"]
var arrCopy = arr
let slice = arr[0..<2]                  // ["hello", "world"]
arr[0] = "bonjour"
arr                                     // ["bonjour", "world", "goodbye"]
arrCopy                                 // ["hello", "world", "goodbye"]
slice                                   // ["hello", "world"]

Điều này cho phép xử lý thống nhất hơn nhiều, vì việc xử lý danh sách kiểu python đơn giản hơn (IMHO) - lọc một danh sách này để tạo một danh sách khác. theo câu trả lời của Matt trước Beta 3, bạn phải tạo một mảng tạm thời để ánh xạ một lát cắt. Mã mới hiện đơn giản hơn:

class NameNumber {
    var name:String = ""
    var number:Int = 0

    init (name:String, number:Int) {
        self.name = name
        self.number = number
    }
}

var number = 1
let names = ["Alan", "Bob", "Cory", "David"]
let foo = names[0..<2].map { n in NameNumber(name:n, number:number++) }
foo     // [{name "Alan" number 1}, {name "Bob" number 2}]

(mặc dù công bằng mà nói, foo vẫn là một phần nhỏ)

Tài liệu tham khảo:

http://adcdownload.apple.com//Developer_Tools/xcode_6_beta_3_lpw27r/xcode_6_beta_3_release_notes__.pdf

Các thay đổi quan trọng, các vấn đề đã được giải quyết, - Ngôn ngữ Swift, Đoạn 1

"Mảng trong Swift đã được thiết kế lại hoàn toàn để có đầy đủ ngữ nghĩa giá trị như Từ điển và Chuỗi ... m"

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.