Slice ใน Swift คืออะไร?


85

Slice ใน Swift คืออะไรและแตกต่างจากอาร์เรย์อย่างไร

จากเอกสารประกอบลายเซ็นประเภทของตัวห้อย (ช่วง) คือ:

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

ทำไมไม่คืนอื่นArray<T>แทนที่จะเป็นSlice<T>?

ดูเหมือนว่าฉันสามารถเชื่อมชิ้นส่วนกับอาร์เรย์ได้:

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

แต่สิ่งนี้ทำให้เกิดข้อผิดพลาด:

ไม่พบโอเวอร์โหลดสำหรับ "ตัวห้อย" ที่ยอมรับอาร์กิวเมนต์ที่ให้มา

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

Slice คืออะไร?

คำตอบ:


97

สไลซ์ชี้ไปที่อาร์เรย์ ไม่มีจุดที่จะสร้างอาร์เรย์อื่นเมื่ออาร์เรย์มีอยู่แล้วและสไลซ์สามารถอธิบายส่วนที่ต้องการได้

การเพิ่มทำให้เกิดการบีบบังคับโดยนัยดังนั้นจึงได้ผล ในการทำงานที่ได้รับมอบหมายคุณจะต้องบังคับ:

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

ที่สมเหตุสมผล มีอธิบายไว้ที่ใดในเอกสารนี้หรือไม่?
hjing

2
เป็นรายละเอียดการใช้งานจริงๆ คุณตรวจสอบเคสขอบที่เผยให้เห็นการทำงานของกล่องดำอย่างชาญฉลาด ... !
แมตต์

2
Slice เป็นสำเนาของอาร์เรย์ หลังจากที่คุณอัปเดตอาร์เรย์เดิมแล้วสไลซ์จะไม่เปลี่ยนแปลง นี่เป็นเพราะธรรมชาติของโครงสร้าง และสำหรับหมายเหตุโปรโตคอล Sliceable ไม่ได้หมายความถึงการใช้งานประเภท Slice
Marcin

4
ภาษาที่รวดเร็วมีการเปลี่ยนแปลงและส่วนหนึ่งใช้จุดไข่ปลาสามจุดจริง ๆ แล้วไม่ใช่สองนักพัฒนา
apple.com/library/ios/documentation/General/Reference/…

7
มันจะไม่ทำให้การติดต่อเสียหายหากคุณเพิ่มการแก้ไขแบบธรรมดาที่แจ้งให้ผู้อ่านใหม่ทราบว่าตัวดำเนินการช่วงมีการเปลี่ยนแปลงหรือไม่?
Daniel Galasko

22

หมายเหตุ:คำตอบนี้ไม่ถูกต้องอย่างมีความสุขใน Swift beta 3 เนื่องจากอาร์เรย์เป็นประเภทค่าจริง


@matt ถูกต้องด้านบน - Slice<T>จุดในอาร์เรย์ ดูเหมือนว่าจะตรงกันข้ามกับวิธีที่ Swift จัดการกับประเภทข้อมูลอื่น ๆ ทั้งหมดที่เรากำลังทำงานด้วยเนื่องจากหมายความว่าค่าของชิ้นสามารถเปลี่ยนแปลงได้แม้ว่าจะประกาศเป็นค่าคงที่:

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

ส่วนที่แย่ที่สุดคือสไลซ์ทำหน้าที่เหมือนกับอาร์เรย์ เนื่องจากใน Swift เรามีความคาดหวังว่าจะไม่เปลี่ยนรูปจึงดูเป็นอันตรายที่ค่าตัวห้อยของชิ้นส่วนสามารถเปลี่ยนแปลงได้โดยไม่มีการเตือน:

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

แต่ถ้าอาร์เรย์ที่อยู่ข้างใต้มีการเปลี่ยนแปลงอย่างรุนแรงเกินไปพวกมันจะถูกปลดออก:

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

6
ในความเป็นจริงชิ้นทำงานเพียงเช่นอาร์เรย์ตามที่คุณพูด สวิฟท์อาร์เรย์มีองค์ประกอบไม่แน่นอนแม้ว่าพวกเขาจะไม่เปลี่ยนรูปการประกาศให้เป็น let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour"ตัวอย่างเช่นลอง คุณจะพบว่ามันใช้งานได้ ด้วยอาร์เรย์ที่ไม่เปลี่ยนรูปจึงเป็นเพียงขนาดที่ไม่เปลี่ยนรูปเท่านั้นไม่ใช่เนื้อหา (ดู "Mutability of Collections" ในThe Swift Programming Language )
Matt Gibson

1
"องค์ประกอบที่เปลี่ยนแปลงไม่ได้" - นี่ไม่ใช่ความจริงอีกต่อไป
Alex Brown

14

สรุป:

คำตอบข้างต้นเป็นจริงจนถึงเบต้า 3 (และอาจมีการเปลี่ยนแปลงอีกครั้งในอนาคต)

ตอนนี้ Slice ทำหน้าที่เหมือนอาร์เรย์ แต่ตามที่ @matt กล่าวไว้ข้างต้นเป็นสำเนาตื้นไปยังอาร์เรย์ที่อยู่ใต้ฝากระโปรงได้อย่างมีประสิทธิภาพจนกว่าจะมีการเปลี่ยนแปลง Slices (ตอนนี้) ดูภาพรวมของค่าดั้งเดิม

โปรดทราบว่าไวยากรณ์ของ Slice มีการเปลี่ยนแปลง:

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

ตัวอย่าง:

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

สิ่งนี้ช่วยให้การประมวลผลแบบสม่ำเสมอมากขึ้นเนื่องจากง่ายกว่า (IMHO) ในการประมวลผลรายการสไตล์หลาม - กรองรายการหนึ่งเพื่อสร้างอีกรายการ ตามคำตอบของ Matt ก่อนเบต้า 3 คุณต้องสร้างอาร์เรย์ชั่วคราวเพื่อแมปชิ้นส่วน ตอนนี้โค้ดใหม่ง่ายขึ้น:

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

(แม้ว่าจะยุติธรรม แต่ foo ก็ยังคงเป็นส่วนหนึ่ง)

อ้างอิง:

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

การเปลี่ยนแปลงที่สำคัญปัญหาที่ได้รับการแก้ไข - ภาษา Swift ย่อหน้าที่ 1

"Array ใน Swift ได้รับการออกแบบใหม่ทั้งหมดเพื่อให้มีความหมายเต็มค่าเช่น Dictionary และ String ... m"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.