0Pricing
Swift Academy · บทเรียน

KeyPath ที่เขียนได้และอ้างอิงได้

อ่านและเขียนผ่านเส้นทางคีย์

KeyPath ที่เขียนได้และอ้างอิงได้ เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คีย์พาธแบบอ่านอย่างเดียวเทียบกับแบบเขียนได้

KeyPath ธรรมดาใช้ read ค่าได้เท่านั้น หากต้องการเขียนค่าผ่านคีย์พาธ คุณต้องใช้รูปแบบที่เขียนได้ Swift มีรูปแบบดังกล่าวสองชนิด ชนิดหนึ่งสำหรับชนิดค่า และอีกชนิดหนึ่งสำหรับชนิดอ้างอิง

บทเรียนนี้ครอบคลุม WritableKeyPath สำหรับโครงสร้างข้อมูลและ ReferenceWritableKeyPath สำหรับคลาส รวมถึงวิธีที่ซับสคริปต์ [keyPath:] กลายเป็นสิ่งที่กำหนดค่าได้

struct Person {
    var name: String
    var age: Int
}

let writable: WritableKeyPath<Person, Int> = \Person.age
print(type(of: writable))

WritableKeyPath สำหรับชนิดค่า

WritableKeyPath ใช้ชี้ไปยังคุณสมบัติที่จัดเก็บและเปลี่ยนแปลงได้ของชนิดค่า หากต้องการกำหนดค่าผ่านคีย์พาธ อินสแตนซ์นั้นต้องเป็น var เพราะการเปลี่ยนคุณสมบัติของโครงสร้างข้อมูลจะเปลี่ยนค่าทั้งหมด

ใช้ซับสคริปต์ [keyPath:] ทางด้านซ้ายของการกำหนดค่าเพื่อเขียนค่า

struct Person {
    var name: String
    var age: Int
}

var alice = Person(name: "Alice", age: 30)
let agePath = \Person.age
alice[keyPath: agePath] = 31
print(alice.age)

เหตุใดอินสแตนซ์จึงต้องเป็น var

สำหรับชนิดค่า การเขียนผ่านคีย์พาธจะเปลี่ยนสำเนาค่าเดิมโดยตรง หากอินสแตนซ์เป็น let ก็ไม่มีสิ่งใดให้เปลี่ยนแปลง ดังนั้นการกำหนดค่าจะคอมไพล์ไม่ผ่าน

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

struct Point {
    var x: Int
    var y: Int
}

var p = Point(x: 1, y: 2)
p[keyPath: \Point.x] = 10
p[keyPath: \Point.y] = 20
print(p)

ตัวช่วยกำหนดค่าแบบทั่วไป

เนื่องจากคีย์พาธแบบเขียนได้เก็บข้อมูลว่าต้องเปลี่ยนคุณสมบัติใด คุณจึงเขียนฟังก์ชันทั่วไปที่อัปเดตคุณสมบัติใดก็ได้ของชนิดค่าใดก็ได้ ส่งอินสแตนซ์ด้วย inout เพื่อให้การเปลี่ยนแปลงถูกเขียนกลับไป

นี่คือพื้นฐานของเครื่องมือขนาดเล็กสำหรับการอัปเดตแบบฟังก์ชัน

func update<Root, Value>(_ root: inout Root, _ path: WritableKeyPath<Root, Value>, to value: Value) {
    root[keyPath: path] = value
}

struct Person { var name: String; var age: Int }
var bob = Person(name: "Bob", age: 40)
update(&bob, \.age, to: 41)
print(bob.age)

ReferenceWritableKeyPath สำหรับคลาส

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

นี่คือความแตกต่างสำคัญจากคีย์พาธแบบเขียนได้ของชนิดค่า

class Counter {
    var value: Int = 0
}

let counter = Counter()
let path: ReferenceWritableKeyPath<Counter, Int> = \Counter.value
counter[keyPath: path] = 5
print(counter.value)

การอ้างอิงแบบ let แต่อ็อบเจ็กต์เปลี่ยนแปลงได้

สังเกตว่าอินสแตนซ์ของคลาสด้านล่างเป็น let แต่เรายังคงกำหนดค่าคุณสมบัติผ่านคีย์พาธได้ หากเป็นโครงสร้างข้อมูลจะเกิดข้อผิดพลาดขณะคอมไพล์

เป็นเพราะการเปลี่ยนคุณสมบัติของคลาสไม่จำเป็นต้องให้อ้างอิงนั้นเปลี่ยนแปลงได้ เพียงคุณสมบัติเองต้องเปลี่ยนแปลงได้เท่านั้น

class Profile {
    var nickname: String = ""
}

let profile = Profile()
let nickPath = \Profile.nickname
profile[keyPath: nickPath] = "Ace"
print(profile.nickname)

ลำดับชั้นชนิดของคีย์พาธ

ชนิดคีย์พาธแบบเขียนได้มีลำดับชั้น ReferenceWritableKeyPath เป็นชนิดย่อยของ WritableKeyPath และ WritableKeyPath เป็นชนิดย่อยของ KeyPath ดังนั้นคีย์พาธที่เฉพาะเจาะจงกว่าจึงใช้ได้ทุกที่ที่ต้องการคีย์พาธทั่วไปกว่า

นั่นหมายความว่าคุณสามารถส่ง ReferenceWritableKeyPath ให้ฟังก์ชันที่ต้องการเพียง read ผ่าน KeyPath ได้

class Box { var size: Int = 1 }

func readSize(_ box: Box, _ path: KeyPath<Box, Int>) -> Int {
    box[keyPath: path]
}

let writable: ReferenceWritableKeyPath<Box, Int> = \Box.size
print(readSize(Box(), writable))

การอัปเดตชนิดค่าที่ซ้อนกัน

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

ที่นี่เราเปลี่ยนค่า city ภายใน address ที่ซ้อนกัน

struct Address { var city: String }
struct Person { var name: String; var address: Address }

var carol = Person(name: "Carol", address: Address(city: "Oslo"))
carol[keyPath: \Person.address.city] = "Bergen"
print(carol.address.city)

การใช้การอัปเดตหลายรายการ

เนื่องจากคีย์พาธแบบเขียนได้เป็นค่า คุณจึงจัดเก็บรายการการอัปเดตเป็นคู่คีย์พาธกับค่า แล้วใช้ apply กับคู่เหล่านั้นในลูปได้ นี่คือระบบแพตช์ขนาดเล็ก

ที่นี่เราใช้ apply การเปลี่ยนแปลงสองรายการกับโครงสร้างข้อมูล settings

struct Settings { var volume: Int; var brightness: Int }

var settings = Settings(volume: 5, brightness: 5)
func apply(_ s: inout Settings, _ path: WritableKeyPath<Settings, Int>, _ v: Int) {
    s[keyPath: path] = v
}
apply(&settings, \.volume, 8)
apply(&settings, \.brightness, 3)
print(settings)

การกำหนดค่าในรูปแบบการเชื่อมต่อ

การใช้งานจริงที่พบได้บ่อยคือสร้างตัวช่วย configure ซึ่งกำหนดคุณสมบัติให้กับอ็อบเจ็กต์ที่เพิ่งสร้าง แล้วคืนค่าอ็อบเจ็กต์นั้นกลับมา ทำให้เขียนโค้ดต่อกันเป็นสายได้ สำหรับคลาส วิธีนี้ใช้ได้กับผลลัพธ์ที่เป็น let

ที่นี่เรากำหนดข้อความของ label ผ่านคีย์พาธอ้างอิงแบบเขียนได้

class Label { var text: String = "" }

func configure<T: AnyObject, V>(_ object: T, _ path: ReferenceWritableKeyPath<T, V>, _ value: V) -> T {
    object[keyPath: path] = value
    return object
}

let label = configure(Label(), \.text, "Hello")
print(label.text)

การเลือกชนิดคีย์พาธที่เหมาะสม

ใช้ KeyPath เมื่อคุณต้องการเพียง read ใช้ WritableKeyPath เพื่อกำหนดคุณสมบัติของชนิดค่าที่เก็บอยู่ใน var และใช้ ReferenceWritableKeyPath เพื่อกำหนดคุณสมบัติของคลาส แม้จะเข้าถึงผ่าน let ก็ตาม

การเลือกชนิดที่เฉพาะเจาะจงที่สุดเท่าที่เหมาะสมช่วยให้ส่วนติดต่อการใช้งานของคุณสื่ออย่างตรงไปตรงมาว่ารองรับการ read หรือการเปลี่ยนแปลงค่า

struct S { var n: Int }
class C { var n: Int = 0 }

let read: KeyPath<S, Int> = \S.n
let writeStruct: WritableKeyPath<S, Int> = \S.n
let writeClass: ReferenceWritableKeyPath<C, Int> = \C.n
print(type(of: read), type(of: writeStruct), type(of: writeClass))

ตรวจสอบด่วน: คีย์พาธแบบเขียนได้

ลองนึกดูว่าคีย์พาธชนิดใดที่ช่วยให้คุณกำหนดค่าคุณสมบัติของคลาสได้ แม้อินสแตนซ์จะเป็นค่าคงที่ let

ทบทวน: คีย์พาธแบบเขียนได้และแบบอ้างอิง

คุณได้เรียนรู้วิธีเขียนค่าผ่านคีย์พาธแล้ว:

  • WritableKeyPath ใช้กำหนดค่าคุณสมบัติที่จัดเก็บของชนิดค่า และต้องใช้อินสแตนซ์แบบ var
  • ReferenceWritableKeyPath ใช้กำหนดค่าคุณสมบัติของคลาส และทำงานได้แม้เข้าถึงผ่าน let
  • ซับสคริปต์ [keyPath:] จะปรากฏทางด้านซ้ายของการกำหนดค่าเพื่อใช้เขียนค่า
  • ชนิดเหล่านี้มีลำดับชั้น ดังนั้นคีย์พาธแบบเขียนได้จึงใช้แทนคีย์พาธแบบอ่านอย่างเดียวได้
  • ตัวกำหนดค่าแบบทั่วไปที่ใช้ inout และตัวช่วย configure ล้วนสร้างขึ้นบนแนวคิดเหล่านี้

ถัดไปคุณจะได้พบกับ @dynamicMemberLookup ซึ่งใช้คีย์พาธเพื่อมอบการเข้าถึงข้อมูลแบบไดนามิกด้วยรูปแบบจุด

struct Person { var name: String; var age: Int }

var dave = Person(name: "Dave", age: 27)
dave[keyPath: \Person.age] = 28
print("Updated age: \(dave.age)")

คำถามที่พบบ่อย

บทเรียน “KeyPath ที่เขียนได้และอ้างอิงได้” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “KeyPath ที่เขียนได้และอ้างอิงได้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “KeyPath ที่เขียนได้และอ้างอิงได้”

อ่านและเขียนผ่านเส้นทางคีย์ คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “KeyPath ที่เขียนได้และอ้างอิงได้” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐาน KeyPath
  2. การใช้ KeyPaths ในคอลเลกชัน
  3. KeyPath ที่เขียนได้และอ้างอิงได้
  4. @dynamicMemberLookup
← กลับไปที่ Swift Academy