ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย
ประมวลผลหน่วยความจำที่ต่อเนื่องกันอย่างมีประสิทธิภาพ
ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
ตัวชี้บัฟเฟอร์คืออะไร
ตัวชี้ที่ระบุชนิดจะเข้าถึงองค์ประกอบได้ครั้งละหนึ่งรายการ UnsafeBufferPointer<T> จะห่อหุ้ม ตัวชี้เริ่มต้นพร้อมจำนวน เพื่อมอบมุมมองที่มีขอบเขตเหนือบล็อกหน่วยความจำที่ต่อเนื่องกัน ซึ่งสอดคล้องกับ Collection
นั่นหมายความว่าคุณสามารถวนซ้ำ เข้าถึงด้วยดัชนี ใช้ map และ reduce ได้ ซึ่งก็คือ API ของคอลเลกชันที่คุ้นเคยทั้งหมดบนหน่วยความจำดิบ
// A buffer pointer = base address + element count
// UnsafeBufferPointer<Int>(start: ptr, count: 5)บัฟเฟอร์แบบอ่านอย่างเดียวกับแบบเปลี่ยนแปลงได้
เช่นเดียวกับตัวชี้เดี่ยว บัฟเฟอร์มีอยู่สองรูปแบบ ได้แก่ UnsafeBufferPointer<T> สำหรับการวนซ้ำแบบอ่านอย่างเดียว และ UnsafeMutableBufferPointer<T> เมื่อต้องการกำหนดค่าให้องค์ประกอบด้วย
let p = UnsafeMutablePointer<Int>.allocate(capacity: 4)
p.initialize(repeating: 0, count: 4)
let buf = UnsafeMutableBufferPointer(start: p, count: 4)
buf[0] = 11
print(buf[0]) // 11การวนซ้ำเหมือนคอลเลกชัน
เนื่องจากตัวชี้บัฟเฟอร์เป็น Collection ลูป for จึงวนผ่านทุกองค์ประกอบตามลำดับ ไม่ต้องคำนวณดัชนีด้วยตนเอง และไม่มีความเสี่ยงที่ลูปจะคลาดเคลื่อนหนึ่งตำแหน่งเอง แต่ ขอบเขตที่คุณระบุ ยังคงเป็นความรับผิดชอบของคุณ
let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 3)
_ = buf.initialize(from: [10, 20, 30])
for value in buf { print(value) } // 10, 20, 30ใช้อัลกอริทึมของคอลเลกชันได้ทันที
map, filter, reduce, enumerated และ indices ทั้งหมดทำงานกับตัวชี้บัฟเฟอร์ได้ ทำให้คุณประมวลผลหน่วยความจำดิบด้วยโค้ดระดับสูงได้ โดยไม่ต้องจัดสรรหน่วยความจำ
let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 4)
_ = buf.initialize(from: [1, 2, 3, 4])
let total = buf.reduce(0, +) // 10
let evens = buf.filter { $0 % 2 == 0 } // [2, 4]
print(total, evens)การจัดสรรบัฟเฟอร์ที่เปลี่ยนแปลงได้
UnsafeMutableBufferPointer<T>.allocate(capacity:) จะจองบล็อกหน่วยความจำและส่งคืนบัฟเฟอร์ให้ในขั้นตอนเดียว แต่คุณยังต้อง initialize ก่อนอ่าน และต้อง deallocate เมื่อใช้งานเสร็จ
let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 5)
buf.initialize(repeating: 0)
defer {
buf.deinitialize()
buf.deallocate()
}ไม่มีการตรวจสอบขอบเขตที่ปลายบัฟเฟอร์
การเข้าถึงด้วยดัชนีภายใน 0..<count นั้นทำได้ แต่บัฟเฟอร์ไม่อาจรู้ได้ว่า จำนวนที่คุณระบุ ถูกต้องหรือไม่ หากคุณสร้างบัฟเฟอร์ด้วยจำนวนที่มากกว่าการจัดสรรจริง การอ่านจะเลยจุดสิ้นสุดเข้าไปในหน่วยความจำที่ไม่มีการกำหนดความหมาย
ให้คำนวณจำนวนจากการจัดสรรเดียวกับที่คุณสร้างเสมอ
let p = UnsafeMutablePointer<Int>.allocate(capacity: 3)
p.initialize(repeating: 0, count: 3)
// CORRECT: count matches capacity
let good = UnsafeBufferPointer(start: p, count: 3)
// WRONG: count: 10 would read past the block
print(good.count)บัฟเฟอร์ว่าง
บัฟเฟอร์ที่มี count: 0 ถือว่าใช้งานได้และอาจมีที่อยู่เริ่มต้นเป็น nil ให้ตรวจสอบ isEmpty เสมอ หรือปล่อยให้ลูปไม่ทำงานแทนการบังคับแกะค่า baseAddress
let empty = UnsafeBufferPointer<Int>(start: nil, count: 0)
print(empty.isEmpty) // true
print(empty.count) // 0
for _ in empty { print("never runs") }withUnsafeBufferPointer บนอาร์เรย์
วิธีที่ปลอดภัยที่สุดในการรับบัฟเฟอร์คือรับจาก Array ที่มีอยู่แล้วผ่าน withUnsafeBufferPointer Swift รับรองว่าพื้นที่จัดเก็บจะต่อเนื่องกันและใช้งานได้ตลอดระยะเวลาของคลอเชอร์ คุณจึงไม่ต้องจัดสรรหน่วยความจำด้วยตนเอง
let numbers = [4, 8, 15, 16, 23]
let maxValue = numbers.withUnsafeBufferPointer { buf -> Int in
var m = buf[0]
for v in buf where v > m { m = v }
return m
}
print(maxValue) // 23การเปลี่ยนแปลงพื้นที่จัดเก็บของอาร์เรย์
withUnsafeMutableBufferPointer ช่วยให้คุณเขียนลงในพื้นที่จัดเก็บของอาร์เรย์ได้โดยตรง วิธีนี้บางครั้งใช้กับการแปลงข้อมูลภายในพื้นที่เดิมที่ต้องการประสิทธิภาพสูง ซึ่ง ARC และการตรวจสอบขอบเขตอาจเพิ่มค่าใช้จ่ายในการทำงาน
var data = [1, 2, 3, 4]
data.withUnsafeMutableBufferPointer { buf in
for i in buf.indices { buf[i] *= 10 }
}
print(data) // [10, 20, 30, 40]baseAddress สำหรับ API ของ C
เมื่อเรียกฟังก์ชัน C ที่ต้องการตัวชี้พร้อมความยาว ให้ส่ง buffer.baseAddress และ buffer.count ที่อยู่เริ่มต้นจะเป็น nil เฉพาะเมื่อบัฟเฟอร์ว่าง ดังนั้นต้องจัดการกรณีนี้ด้วย
let bytes: [UInt8] = [0xDE, 0xAD, 0xBE, 0xEF]
bytes.withUnsafeBufferPointer { buf in
if let base = buf.baseAddress {
// c_function(base, buf.count)
print("start:", base, "len:", buf.count)
}
}เมื่อใดควรใช้ตัวชี้บัฟเฟอร์
ใช้ตัวชี้บัฟเฟอร์เมื่อต้องการเข้าถึงพื้นที่หน่วยความจำแบบต่อเนื่อง ซึ่งมีชนิดข้อมูลปลอดภัยและมีรูปแบบเหมือนคอลเลกชัน เช่น การเชื่อมอาร์เรย์ C การแยกวิเคราะห์รูปแบบไบนารี หรือการลดค่าใช้จ่ายในลูปที่ทำงานบ่อย ๆ หากเป็นไปได้ ให้เลือกรูปแบบคลอเชอร์ with... แทนการจัดสรรหน่วยความจำด้วยตนเอง
// Counting set bits across a byte buffer
let data: [UInt8] = [0b1011, 0b0110, 0b1111]
let bits = data.withUnsafeBufferPointer { buf in
buf.reduce(0) { $0 + $1.nonzeroBitCount }
}
print(bits) // 3 + 2 + 4 = 9ตรวจสอบความเข้าใจ
ลองทบทวนว่าตัวชี้บัฟเฟอร์เพิ่มความสามารถอะไรจากตัวชี้เดี่ยว
สรุป
ตัวชี้บัฟเฟอร์จะห่อหุ้มพื้นที่หน่วยความจำที่ต่อเนื่องกันให้เป็นคอลเลกชันที่มีขอบเขต:
UnsafeBufferPointer/UnsafeMutableBufferPointer= ที่อยู่เริ่มต้น + จำนวน- คุณจะได้
map,filter,reduceและการวนซ้ำด้วยforบนหน่วยความจำดิบ - เลือกใช้
withUnsafeBufferPointerกับอาร์เรย์ เพื่อให้ Swift จัดการความถูกต้องและอายุการใช้งาน - ระบบจะเชื่อถือจำนวนที่ระบุ ดังนั้นให้คำนวณจากการจัดสรรจริง
คำถามที่พบบ่อย
บทเรียน “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย”
ประมวลผลหน่วยความจำที่ต่อเนื่องกันอย่างมีประสิทธิภาพ คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม
ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- MemoryLayout และการจัดแนว
- UnsafePointer และ UnsafeMutablePointer
- ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย
- withUnsafeBytes และการทำงานร่วมกับ C