Result Builder — คืออะไร ไวยากรณ์ และการประยุกต์ใช้

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-20 เวลาอ่าน: 8 นาที

Result Builder คือแอตทริบิวต์ของ Swift ที่ใช้งานผ่านโปรโตคอล @resultBuilder ซึ่งแปลงลำดับของนิพจน์ให้เป็นค่าผสม คอมไพเลอร์จะแปลงบล็อกโค้ดที่มีโครงสร้างควบคุม if, for, switch เป็นการเรียกเมธอดสแตติกของ builder — buildBlock, buildEither, buildArray ตามข้อเสนอ Swift Evolution SE-0289 (2022) result builders ช่วยให้สร้าง DSL แบบประกาศภายใน Swift ได้โดยไม่ต้องใช้ตัวแยกวิเคราะห์ภายนอก ตัวอย่างที่รู้จักกันดีคือ @ViewBuilder ใน SwiftUI ซึ่งบอดีของ view ถูกสร้างจากองค์ประกอบแบบมีเงื่อนไขและแบบวนซ้ำในสไตล์การประกาศ

ประเด็นสำคัญ

  • Result Builder — แอตทริบิวต์ Swift ที่แปลงลำดับของนิพจน์เป็นค่าผลลัพธ์ผ่านเมธอดสแตติกของ builder
  • @ViewBuilder — ตัวอย่างที่รู้จักกันดีที่สุด: มันแปลงหลาย view เป็นการแสดงผลแบบผสมเดียว TupleView
  • โครงสร้างควบคุม — builder รองรับ if/else, switch, for-in ผ่านเมธอด buildOptional, buildEither, buildArray
  • Builder ที่กำหนดเอง สามารถสร้างสำหรับ DSL ของคุณเอง — HTML, CSS, การกำหนดค่า, คำสั่งค้นหา
  • Swift 5.4 ขยายการรองรับ result builders ไปยังฟังก์ชันและพารามิเตอร์ของฟังก์ชัน — ตอนนี้คุณสามารถใช้ builder กับอาร์กิวเมนต์ closure

Result Builder คืออะไร?

Result Builder (เดิมรู้จักในชื่อ function builders) เป็นกลไกของ Swift ที่ช่วยให้เปลี่ยนลำดับของนิพจน์ที่คั่นด้วยการขึ้นบรรทัดใหม่เป็นค่าเดียว ถูกประกาศโดยใช้แอตทริบิวต์ @resultBuilder ที่ใช้กับโครงสร้างซึ่ง implement เมธอดการแปลงแบบสแตติก

ก่อนมี result builders ไวยากรณ์แบบประกาศของ SwiftUI body เป็นไปไม่ได้ แทนที่จะเป็นรายการ view ที่กะทัดรัด นักพัฒนาจะต้องเขียนการเรียก TupleView ด้วยตนเอง Result Builder จะห่อหุ้มแต่ละนิพจน์โดยอัตโนมัติ รองรับการแยกสาขาและลูป ซ่อนความซับซ้อนของการประกอบจากนักพัฒนา

ตาม Swift Evolution SE-0289 ที่ได้รับการยอมรับในปี 2022 result builder คือวิวัฒนาการของแนวคิด function builders (SE-0258, Swift 5.1) การเปลี่ยนแปลงหลัก: การเปลี่ยนชื่อจาก @_functionBuilder เป็น @resultBuilder และขยายไปยังพารามิเตอร์ของฟังก์ชัน ทำให้สามารถใช้ builders สำหรับอาร์กิวเมนต์ closure ใด ๆ ไม่ใช่แค่บอดีของ view

ใช้ result builders เมื่อคุณต้องการให้ผู้ใช้ไลบรารีของคุณมีไวยากรณ์แบบประกาศสำหรับสร้างโครงสร้างที่ซับซ้อน — การกำหนดค่า, คำสั่งค้นหา, ส่วนประกอบ UI — โดยไม่ต้องเขียนโค้ดประกอบแบบ'imperative

Result Builder ทำงานอย่างไร

คอมไพเลอร์ Swift แปลงแต่ละบล็อกโค้ดที่ทำเครื่องหมายด้วย @resultBuilder เป็นลำดับของการเรียกเมธอดสแตติกของ builder มาดู builder ง่าย ๆ ที่เชื่อมสตริง:

swift
@resultBuilder
struct StringBuilder {
    static func buildBlock(_ parts: String...) -> String {
        parts.joined(separator: " ")
    }
}

การใช้ builder นี้ — แต่ละสตริงในบรรทัดแยกกันจะถูกเชื่อมด้วยช่องว่าง:

swift
@StringBuilder
func greeting() -> String {
    "Hello"
    "World"
    "from"
    "Swift"
}
// คอมไพเลอร์แปลงค่านี้เป็น:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// ผลลัพธ์: "Hello World from Swift"

คอมไพเลอร์จัดกลุ่มนิพจน์ที่ต่อเนื่องกันและส่งเป็นพารามิเตอร์ variadic ไปยัง buildBlock หากมี if ปรากฏระหว่างนิพจน์ คอมไพเลอร์จะเรียก buildOptional หรือ buildEither สำหรับการแยกสาขา สำหรับลูป for-in มันจะเรียก buildArray ดังนั้น โค้ด Swift ปกติจะถูกแปลงเป็นห่วงโซ่การเรียกที่สร้างค่าสุดท้าย

เมธอดของ builder: buildBlock, buildOptional, buildEither

แต่ละ result builder กำหนดชุดเมธอดสแตติกที่คอมไพเลอร์เรียกระหว่างการแปลง เมธอดหลัก:

เมธอดวัตถุประสงค์เมื่อถูกเรียก
buildBlockรวมลำดับของนิพจน์สำหรับแต่ละบล็อกที่ไม่มีการแยกสาขา
buildOptionalจัดการ if ที่ไม่มี elseเมื่อมี if โดยไม่มี else
buildEither(first:)สาขาแรกของ if-elseเมื่อมี if กับ else
buildEither(second:)สาขาที่สองของ if-elseเมื่อมี if กับ else
buildArrayจัดการลูป for-inเมื่อมี for-in
buildExpressionแปลงนิพจน์แต่ละตัวสำหรับแต่ละนิพจน์ก่อนส่งไปยัง buildBlock
buildFinalResultการแปลงสุดท้ายก่อนกลับจาก closure

การ implement ขั้นต่ำต้องการเพียง buildBlock ที่มีพารามิเตอร์ variadic — เพียงพอสำหรับบล็อกที่ไม่มีการแยกสาขา การเพิ่ม buildOptional และ buildEither รวมถึงการรองรับโครงสร้างแบบมีเงื่อนไข และ buildArray สำหรับลูป ตามเอกสาร Swift (2025) แนะนำให้ implement ทุกเมธอดเพื่อความยืดหยุ่นสูงสุดของ DSL

buildExpression อนุญาตให้รับนิพจน์ประเภทต่าง ๆ และแปลงเป็นประเภท builder เดียว ตัวอย่างเช่น ใน @ViewBuilder buildExpression รับ Text, Image, Button และแปลงเป็นประเภท View ทั่วไป

การสร้าง Result Builder ที่กำหนดเอง

มาดูการสร้าง builder สำหรับสร้างสตริง HTML กัน DSL นี้จะช่วยให้เขียน HTML แบบประกาศได้โดยตรงใน Swift:

swift
@resultBuilder
enum HTMLBuilder {
    static func buildBlock(_ components: String...) -> String {
        components.joined()
    }

    static func buildOptional(_ component: String?) -> String {
        component ?? ""
    }

    static func buildEither(first component: String) -> String {
        component
    }

    static func buildEither(second component: String) -> String {
        component
    }

    static func buildArray(_ components: [String]) -> String {
        components.joined()
    }
}

การใช้ builder ที่กำหนดเองเพื่อสร้าง HTML:

swift
func div(@HTMLBuilder _ content: () -> String) -> String {
    "<div>\(content())</div>"
}

func p(_ text: String) -> String {
    "<p>\(text)</p>"
}

let page = div {
    p("Hello")
    p("World")

    if showFooter {
        p("ส่วนท้าย")
    }
}
// ผลลัพธ์: <div><p>Hello</p><p>World</p><p>Footer</p></div>

ตามบทความ “Building Custom Result Builders in Swift” จาก Swift.org (2025) builders ที่กำหนดเองถูกใช้ในไลบรารีเพื่อสร้างไฟล์การกำหนดค่า ส่วนประกอบ UI การแมปข้อมูล และแม้แต่คำสั่งค้นหาฐานข้อมูล — ทุกที่ที่ต้องการไวยากรณ์แบบประกาศพร้อมการรองรับการแยกสาขา

@ViewBuilder ใน SwiftUI

@ViewBuilder คือ result builder ที่สร้างใน SwiftUI ซึ่งใช้กับพารามิเตอร์ content ของ view คอนเทนเนอร์ส่วนใหญ่: VStack, HStack, ZStack, Group, List และคุณสมบัติ body เอง มันช่วยให้เขียนหลาย view ในบรรทัดแยกกันโดยไม่ต้องใช้เครื่องหมายจุลภาคหรือตัวห่อหุ้ม

@ViewBuilder implement ทุกเมธอดของ result builder รวมถึงการรองรับ if-else, switch และ for-in เมื่อเงื่อนไขเป็นจริง buildEither(first:) จะคืนค่า view หนึ่ง เมื่อเป็นเท็จ buildEither(second:) จะคืนค่าอีก view หนึ่ง ทั้งสองสาขาต้องคืนค่าประเภทเดียวกัน แต่ SwiftUI ใช้ AnyView ภายในหรือการลบประเภทผ่าน ConditionalContent

swift
struct GreetingView: View {
    let isLoggedIn: Bool

    var body: some View {
        VStack {
            Image(systemName: "person.circle")
            Text("โปรไฟล์")
                .font(.title)

            if isLoggedIn {
                Text("ยินดีต้อนรับกลับ!")
                    .foregroundColor(.green)
            } else {
                Button("เข้าสู่ระบบ") { }
            }
        }
    }
}

หากไม่มี @ViewBuilder โค้ดเดียวกันจะต้องใช้ Group สำหรับแต่ละส่วนแบบมีเงื่อนไขหรือใช้ AnyView ซึ่งทำให้ประสิทธิภาพลดลง @ViewBuilder จะเลือกการแสดงผลที่มีประสิทธิภาพที่สุดโดยอัตโนมัติ — ConditionalContent หรือ TupleView — สำหรับแต่ละชุดค่าผสม

ข้อจำกัดของ Result Builder

ข้อจำกัดแรกคือ จำนวนนิพจน์สูงสุด ใน buildBlock ไลบรารีมาตรฐาน Swift กำหนดโอเวอร์โหลดของ buildBlock สำหรับ 2–10 นิพจน์ หากบล็อกมีมากกว่า 10 นิพจน์ คอมไพเลอร์จะแสดงข้อผิดพลาด วิธีแก้ไขคือการจัดกลุ่มผ่าน Group หรือ VStack เพื่อแบ่งเป็นบล็อกย่อย

ข้อจำกัดที่สองคือ การขาดการรองรับ ตัวแปรและการกำหนดค่าภายในบล็อก builder ไม่สามารถประกาศ let x = 5 ภายใน @ViewBuilder นิพจน์ทั้งหมดต้องเป็นนิพจน์ที่คืนค่าประเภทของ builder สำหรับการคำนวณระหว่างกลาง ให้ใช้การคำนวณนอก builder หรือ buildExpression ที่รองรับประเภทต่าง ๆ

ข้อจำกัดที่สามคือ ความซับซ้อนในการดีบัก ข้อผิดพลาดการคอมไพล์ภายใน result builder มักสร้างข้อความที่สับสน โดยเฉพาะเมื่อประเภทไม่ตรงกันในสาขา if/else ใช้ประเภทส่งคืนที่ชัดเจนและ AnyView สำหรับการดีบัก แม้ว่าอย่างหลังจะลดประสิทธิภาพ ตาม Hacking with Swift (2025) คำแนะนำเชิงปฏิบัติ — เริ่มต้นด้วย builder ง่าย ๆ โดยไม่มีการแยกสาขาและค่อย ๆ เพิ่มการรองรับโครงสร้างแบบมีเงื่อนไข

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

Result Builder ใน Swift คืออะไร?

Result Builder คือแอตทริบิวต์ Swift ที่แปลงลำดับของนิพจน์เป็นค่าผลลัพธ์ผ่านเมธอดสแตติก มันช่วยให้สร้าง DSL แบบประกาศได้ ตัวอย่างที่รู้จักกันดีคือ @ViewBuilder ใน SwiftUI สำหรับสร้างลำดับชั้น view โดยไม่ต้องใช้โค้ดแบบ imperative

จะสร้าง Result Builder ของตัวเองได้อย่างไร?

ประกาศโครงสร้างด้วยแอตทริบิวต์ @resultBuilder และ implement อย่างน้อยเมธอด buildBlock เพื่อรองรับเงื่อนไข เพิ่ม buildOptional และ buildEither สำหรับลูป เพิ่ม buildArray ใช้แอตทริบิวต์ builder ก่อนพารามิเตอร์ closure ในฟังก์ชัน

เมธอดใดที่จำเป็นสำหรับ Result Builder?

เฉพาะ buildBlock เท่านั้นที่จำเป็น เมธอดอื่น ๆ ทั้งหมด — buildOptional, buildEither, buildArray, buildExpression, buildFinalResult — เป็นทางเลือกและเพิ่มการรองรับโครงสร้างที่เกี่ยวข้อง ยิ่ง implement เมธอดมากเท่าไหร่ DSL ก็ยิ่งยืดหยุ่นมากขึ้นเท่านั้น

ทำไม @ViewBuilder ถึงเป็น Result Builder?

@ViewBuilder คือการ implement ที่เป็นรูปธรรมของ result builder สำหรับโปรโตคอล View มันถูกกำหนดใน SwiftUI เป็นโครงสร้างที่มีแอตทริบิวต์ @resultBuilder ซึ่งให้เมธอด buildBlock สำหรับจำนวน view ที่แตกต่างกัน (TupleView), buildEither สำหรับ ConditionalContent และ buildArray สำหรับ ForEach

มีข้อจำกัดเกี่ยวกับจำนวนนิพจน์ใน builder หรือไม่?

ใช่ โอเวอร์โหลด buildBlock มาตรฐานรองรับสูงสุด 10 นิพจน์ เมื่อเกินนี้ ให้ใช้คอนเทนเนอร์แบบซ้อน (Group, VStack) เพื่อแบ่งเป็นบล็อกย่อย builder ที่กำหนดเองสามารถกำหนด buildBlock แบบ variadic โดยไม่มีข้อจำกัด

สรุป

  • Result Builder — แอตทริบิวต์ Swift ที่แปลงลำดับของนิพจน์เป็นค่าเดียวผ่านเมธอดสแตติกของ builder
  • คอมไพเลอร์ แทนที่บล็อกโค้ดด้วยการเรียก buildBlock, buildEither, buildOptional, buildArray ขึ้นอยู่กับโครงสร้างควบคุม
  • @ViewBuilder — result builder ในตัวของ SwiftUI ที่ช่วยให้เขียนโค้ดลำดับชั้น view แบบประกาศพร้อมการรองรับเงื่อนไขและลูป
  • Builder ที่กำหนดเอง ใช้สำหรับสร้าง DSL: HTML, การกำหนดค่า, คำสั่งค้นหา — โครงสร้างใด ๆ ที่ได้รับประโยชน์จากไวยากรณ์แบบประกาศ
  • ข้อจำกัด: สูงสุด 10 นิพจน์ใน buildBlock, ไม่สามารถประกาศตัวแปร, ข้อผิดพลาดการคอมไพล์ที่สับสนเมื่อประเภทไม่ตรงกัน
  • Swift 5.4+ — สามารถใช้ builder กับพารามิเตอร์ของฟังก์ชัน ขยายกรณีการใช้งานนอกเหนือจากบอดีของ view

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม