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

โคลเชอร์

โคลเชอร์

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

บทนำ

สวัสดีครับ/ค่ะ

คลอเชอร์คือบล็อกโค้ดที่ทำงานได้ในตัวเอง คลอเชอร์สามารถส่งเป็นพารามิเตอร์ให้กับโค้ด หรือใช้งานภายในโค้ดได้

คลอเชอร์เป็นชนิดหนึ่งของฟังก์ชัน สามารถนำไปใช้งานโดยส่งเข้าไปในโค้ดได้ และมีลักษณะคล้ายแลมบ์ดาในภาษาการเขียนโปรแกรมอื่น ๆ

การจัดการหน่วยความจำ

ประเด็นสำคัญประการหนึ่งคือ คลอเชอร์สามารถเก็บค่าของค่าคงที่และตัวแปรในบริบทที่มีการกำหนดคลอเชอร์นั้นไว้ได้

การเก็บค่านี้เรียกว่าการปิดล้อมค่า

สวิฟต์จัดการหน่วยความจำระหว่างการเก็บค่านี้ให้เรา

ชนิดของคลอเชอร์

คลอเชอร์มีอยู่หลายชนิด

  1. ฟังก์ชันระดับโกลบอล คือคลอเชอร์ที่มีชื่อ และฟังก์ชันเหล่านี้จะไม่เก็บค่าใด ๆ
  2. ฟังก์ชันซ้อน สามารถเก็บค่าของชื่อและฟังก์ชันที่ห่อหุ้มอยู่ภายในได้
  3. นิพจน์คลอเชอร์ เป็นคลอเชอร์ที่ไม่มีชื่อ และสามารถเก็บข้อมูลจากบริบทที่ล้อมรอบตัวเองได้ด้วยไวยากรณ์ที่เรียบง่าย

ไวยากรณ์ของคลอเชอร์

มีการพยายามทำให้ไวยากรณ์ของคลอเชอร์เรียบง่ายที่สุด สิ่งสำคัญมีดังนี้

  • สามารถอนุมานพารามิเตอร์ในคลอเชอร์ได้
  • สามารถอนุมานค่าที่คืนกลับได้
  • สามารถเขียนการคืนค่าจากคลอเชอร์ในบรรทัดเดียวได้
  • สามารถใช้ชื่อย่อ เช่น $ 0 หรือ $ 1 แทนชื่ออาร์กิวเมนต์ได้
  • สามารถใช้ไวยากรณ์คลอเชอร์ต่อท้ายได้

ข้อมูล

นิพจน์คลอเชอร์หมายถึงการเขียนคลอเชอร์แบบแทรกในบรรทัดเดียว โดยเน้นไวยากรณ์และความเรียบง่าย

ไวยากรณ์คลอเชอร์

ตัวอย่างไวยากรณ์คลอเชอร์แสดงอยู่ในโค้ดด้านล่าง

{ (parameters) -> return type in
    statements
}


func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
//If we didn't use closures, our code structure would be as follows.

var reversedNames = names.sorted(by: backward)

ไวยากรณ์คลอเชอร์

อย่างไรก็ตาม เมื่อใช้คลอเชอร์ เราไม่จำเป็นต้องกำหนดคลอเชอร์ระดับโกลบอลที่มีชื่อโดยไม่จำเป็น

เพียงกำหนดนิพจน์คลอเชอร์อย่างง่ายในพารามิเตอร์ก็เพียงพอแล้ว มาดูตัวอย่างกัน

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

///sorted method takes closure as parameter.

คีย์เวิร์ด in

เราจะเข้าใจจากคีย์เวิร์ด in ว่าเนื้อหาของคลอเชอร์เริ่มต้นขึ้น

ก่อนคีย์เวิร์ด in ต้องกำหนดพารามิเตอร์ที่คลอเชอร์รับมาและชนิดค่าที่คืนกลับ

การอนุมานชนิดจากบริบท

การอนุมานชนิดจากบริบท

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

ดังนั้นเราจึงไม่จำเป็นต้องกำหนดสิ่งเหล่านี้เพิ่มเติม

ในตัวอย่างนี้ จะอนุมานได้ว่า เนื่องจากค่าในอาร์เรย์ names เป็นสตริง พารามิเตอร์ที่คลอเชอร์รับมาจึงเป็นชนิดสตริง

เช่นเดียวกัน คลอเชอร์ที่เกี่ยวข้องต้องใช้ค่าชนิดบูลีนเพื่อจัดเรียง ดังนั้นชนิดค่าที่คืนกลับจึงอนุมานเป็นชนิดบูลีน

ตัวอย่าง

วิธีใช้งานด้านล่างจะเรียบง่ายขึ้น

นอกจากนี้ยังสามารถละเครื่องหมายลูกศรออกจากโค้ดได้ด้วยการอนุมานชนิดค่าที่คืนกลับ

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

ไวยากรณ์แบบย่อ

ควรใช้ไวยากรณ์แบบเต็มแทนไวยากรณ์แบบย่อ เพื่อไม่ให้ผู้อ่านโค้ดสับสน

ไวยากรณ์ข้างต้นยังสามารถย่อให้สั้นลงได้อีก

สามารถย่อค่าที่คืนกลับด้วยนิพจน์คลอเชอร์ได้โดยนำคีย์เวิร์ด return ออก

/*
In this example, the return keyword has been extracted.
It already has single expression. 
There is no need to express it as an extra with return.
*/

var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
print(reversedNames)

ตัวอย่าง

ในตัวอย่างนี้ ได้นำคีย์เวิร์ด return ออกแล้ว

เนื่องจากมีนิพจน์เพียงนิพจน์เดียว จึงไม่จำเป็นต้องระบุ return เพิ่มเติม

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

ชื่อย่อ

ไวยากรณ์สามารถย่อให้สั้นลงได้อีก ในตัวอย่างข้างต้น เราระบุว่าคลอเชอร์รับพารามิเตอร์สองตัว ได้แก่ s1 และ s2 โดยอนุมานชนิดของพารามิเตอร์เหล่านี้ได้

ตอนนี้เราสามารถใช้ชื่อย่อแทนพารามิเตอร์เหล่านี้ได้ โดยไม่ต้องเขียนและกำหนดพารามิเตอร์ด้วยตัวเอง

นอกจากนี้ เนื่องจากไม่มีการกำหนดพารามิเตอร์และส่งค่าที่คืนกลับ จึงสามารถละคีย์เวิร์ด in ได้เช่นกัน

let names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { $0 > $1 } )
print(reversedNames)

// In this example $0 will shortcut the first parameter and $1 will shortcut the second parameter.

ตัวอย่างการย่อ

var names = ["Coddy", "Kit"]

let reversedNames = names.sorted(by: >)
print(reversedNames)
// Greater than operator takes two parameters and the rotation type is squat.

TRAILING CLOSURE

คลอเชอร์ต่อท้าย

หากพารามิเตอร์ที่ส่งให้ฟังก์ชันคลอเชอร์เป็นอาร์กิวเมนต์สุดท้ายของฟังก์ชัน และนิพจน์คลอเชอร์มีความยาวมาก การเขียนในรูปคำสั่งคลอเชอร์ต่อท้ายอาจมีประโยชน์มากกว่า

เราสามารถใช้คลอเชอร์ต่อท้ายเป็นไวยากรณ์แบบย่อได้ ซึ่งช่วยเพิ่มความสามารถในการอ่านโค้ด

พารามิเตอร์สุดท้ายของเมธอดส่วนใหญ่ใน iOS คือคลอเชอร์

พารามิเตอร์สุดท้าย

ตัวอย่างเช่น ในตัวอย่างนี้ พารามิเตอร์สุดท้ายคือคลอเชอร์

class Animator {
    class func animate(withDuration duration: Double, animations: () -> Void) {
        animations()
    }
}

class MyViewController {
    func start() {
        // With the traditional method, we can call this fund as follows.
        Animator.animate(withDuration: 1, animations: { [unowned self] in
            print("red")
        })
    }
}
MyViewController().start()

เนื่องจากโค้ดด้านบนอ่านได้ยาก จึงเขียนได้ดังนี้

เนื่องจากโค้ดด้านบนอ่านได้ยาก จึงเขียนได้ดังนี้

import Foundation
Thread.sleep(forTimeInterval: 1)
print("Background color changed to red")

ตัวอย่าง

เมื่อใช้ไวยากรณ์คลอเชอร์ต่อท้าย เราไม่จำเป็นต้องเขียนป้ายกำกับอาร์กิวเมนต์

เพราะตอนนี้คลอเชอร์กลายเป็นส่วนหนึ่งของการเรียกใช้ฟังก์ชันแล้ว

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // function body goes here
}

// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
    // closure's body goes here
})

// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

ไวยากรณ์

เราสามารถมองไวยากรณ์คลอเชอร์ต่อท้ายเป็นไวยากรณ์แบบย่อได้ เพราะช่วยให้โค้ดอ่านง่ายขึ้น

/*
In the example below, animations
are expressed as closure.
*/
public class func animate(withDuration: TimeInterval, animations: () -> Void)

// In traditional usage, we need to make a call like the following.
UIView.animate(withDuration: 1, animations: { [unowned self] in
    self.view.backgroundColor = UIColor.red
})

/*
In this way, both the readability of the code
increases and we avoid the use of extra brackets.
If it is as above and the last parameter of the method 
is closure, Swift allows to make a call like the one below.
*/

UIView.animate(withDuration: 1) { [unowned self] in
    self.view.backgroundColor = UIColor.red
}

เราสามารถใช้โค้ดด้านล่างเพื่อทดสอบโค้ด

เราสามารถใช้โค้ดด้านล่างเพื่อทดสอบโค้ดได้


func greetThenRunClosure(name: String, closure: () -> ()) {
    print("Hello, \(name)!")
    closure()
}

greetThenRunClosure(name: "Paul") {
    print("The closure was run")
}

การจับค่าของคลอเชอร์

การจับค่าของคลอเชอร์

คลอเชอร์สามารถเก็บค่าของตัวแปรในสภาพแวดล้อมที่ล้อมรอบคลอเชอร์ได้ และยังสามารถเปลี่ยนค่าของตัวแปรเหล่านี้จากภายในตัวคลอเชอร์เอง รวมถึงเข้าถึงตัวแปรเหล่านั้นได้

แม้ว่าตัวแปรเหล่านี้จะไม่ได้อยู่ในขอบเขตเดิมที่มีการกำหนดตัวแปรไว้ก็ตาม

ต่อ

โดยทั่วไป ข้อมูลนี้สามารถเก็บไว้ในฟังก์ชันซ้อนร่วมกับนิพจน์คลอเชอร์ได้ คลอเชอร์สามารถเก็บข้อมูลของฟังก์ชันภายนอกไว้ได้

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)

print(incrementByTen())
// returns a value of 10
print(incrementByTen())
// returns a value of 20
print(incrementByTen())
// returns a value of 30

ต่อ

หากกำหนดคลอเชอร์เป็นคุณสมบัติของคลาส คลอเชอร์จะเริ่มเก็บการอ้างอิงถึงอินสแตนซ์นี้ไว้

ดังนั้นจะเกิดวงจรการอ้างอิงแบบแข็งแรงระหว่างคลอเชอร์กับอินสแตนซ์

ควรใส่ใจเป็นพิเศษเพื่อป้องกันหน่วยความจำรั่วไหล

คำเตือน

คลอเชอร์และฟังก์ชันเป็นชนิดอ้างอิง

@escaping

เราอาจจำเป็นต้องใช้รูปแบบนี้ในหลายกรณีที่คลอเชอร์ทำงานแบบอะซิงโครนัส

ในสวิฟต์รุ่นแรก ๆ (รุ่น 1 และ 2) คลอเชอร์ในพารามิเตอร์ของสวิฟต์จะสามารถหลุดขอบเขตได้ และต่อมากลายเป็นคลอเชอร์แบบไม่หลุดขอบเขต หากต้องการส่งคลอเชอร์แบบไม่หลุดขอบเขต เราต้องระบุเป็นพิเศษ

ในรุ่นถัดมา พารามิเตอร์คลอเชอร์ถูกกำหนดให้เป็นแบบไม่หลุดขอบเขต เพื่อประหยัดการใช้หน่วยความจำ

ปัจจุบัน หากต้องการกำหนดคลอเชอร์ให้หลุดขอบเขต เราต้องใช้คีย์เวิร์ด @escaping

@ESCAPING คีย์เวิร์ด

คีย์เวิร์ด @ESCAPING

หากต้องการเรียกใช้คลอเชอร์ที่ส่งให้ฟังก์ชันหลังจากฟังก์ชันทำงานเสร็จแล้ว เราจำเป็นต้องระบุคีย์เวิร์ด @escaping

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

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

nonEscaping

ก่อนอื่น มาดูการทำงานของคลอเชอร์แบบ nonEscaping กัน

เมื่อส่งคลอเชอร์นี้เป็นพารามิเตอร์ให้ฟังก์ชัน คลอเชอร์จะถูกประมวลผลภายในตัวฟังก์ชัน จากนั้นจึงคืนการควบคุมให้คอมไพเลอร์

หลังจากฟังก์ชันคืนค่า หรือกล่าวคือหลังจากการทำงานเสร็จสิ้น คลอเชอร์จะอยู่นอกขอบเขตและถูกปล่อยออกจากหน่วยความจำ

การใช้คลอเชอร์แบบหลุดขอบเขต

การใช้คลอเชอร์แบบหลุดขอบเขต

เมื่อส่งฟังก์ชันคลอเชอร์เป็นอาร์กิวเมนต์ คลอเชอร์จะยังคงถูกเก็บรักษาไว้ แม้ฟังก์ชันคลอเชอร์จะคืนค่าและการทำงานเสร็จสิ้นแล้ว

คลอเชอร์จะใช้พื้นที่ในหน่วยความจำจนกว่าจะถูกเรียกใช้ คลอเชอร์แบบหลุดขอบเขตมีอยู่หลายประเภท

ขอแสดงความยินดี

ขอแสดงความยินดี 🎉

เราได้เรียนมาถึงช่วงท้ายของบทเรียนแล้ว 

พบกันในบทเรียนถัดไป 😎

โคลเชอร์ — ภาพประกอบ 29

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

บทเรียน “โคลเชอร์” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “โคลเชอร์”

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

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

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

บทเรียน “โคลเชอร์” ใช้เวลานานแค่ไหน

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

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

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

← กลับไปที่ Swift Academy