# Function

การประกาศฟังก์ชั่นใน Swift จะมีหน้าตาประมาณนี้

```swift
func greet(person: String) -> String {
    return "Hello, " + person + "!"
}
```

เริ่มด้วย keyword `func` จากนั้นเป็นชื่อฟังก์ชั่น ตัวอย่างนี้คือ `greet` จากนั้นจะเป็นวงเล็บ ในวงเล็บจะเป็น argument ที่จะส่งให้กับฟังก์ชั่น ถ้าฟังก์ชั่นให้ผลลัพธ์ออกมา จะตามด้วยเครื่องหมาย `->` แล้วตามด้วย Type ของผลลัพธ์จากฟังก์ชั่น&#x20;

ในฟังก์ชั่น เราใช้ keyword `return` ในการคืนผลลัพธ์ออกจากฟังก์ชั่น

วิธีการเรียกใช้&#x20;

```swift
let greetingMessage = greet(person: "pop")
```

ผลลัพธ์เก็บใน `greetingMessage` จากการเรียกฟังก์ชั่น `greet` ส่ง `"Pop"` เป็น input argument person ของฟังก์ชั่น

โดยปกติเวลาเขียน function signature แบบย่อ ๆ ของฟังก์ชั่นนี้เราจะเขียนได้ ประมาณนี้ `greet(person:)`&#x20;

ฟังก์ชั่นสามารถส่งออกผลลัพธ์ได้แค่ Type เดียว ถ้าต้องการหลายผลลัพธ์เราอาจใช้ Tuple ช่วยได้แบบนี้

```swift
func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
```

ฟังก์ชั่นในภาษา Swift สามารถมีชื่อตัวแปรได้สองชื่อต่อหนึ่งตัว นั่นคือ&#x20;

1. Argument label เป็น label ตอนเรียกใช้งานจากภายนอกฟังก์ชั่น
2. Parameter name ใช้งานภายในฟังก์ชั่น

(ในกรณีที่มีชื่อเดียว จะทำหน้าที่เป็นทั้ง argument label และ parameter name แบบฟังก์ชั่นที่เราเขียนกันไปแล้ว)

หน้าตาจะประมาณนี้&#x20;

```swift
func someFunction(argumentLabel parameterName: Int) {

}
```

เช่น&#x20;

```swift
func greet(person: String, from hometown: String) -> String {
    return "Hello \(person)! from \(hometown)."
}
```

จะเห็นว่า argument ที่สองของฟังก์ชั่นมี argument label ว่า `from` และมี parameter name ว่า `hometown` เวลาเรียกฟังก์ชั่นจากภายนอกจะเป็นแบบนี้

```swift
greet(person: "John", from: "Bangkok")
```

ทำให้เราอ่านแล้วลื่นไหล ทั้งจากโค้ดที่เรียกฟังก์ชั่นและโค้ดที่อยู่ในฟังก์ชั่น เพราะบริบทต่างกัน

{% hint style="info" %}
เวลาเขียน signature จะหน้าตาแบบนี้ `greet(person:from:)`&#x20;
{% endhint %}

ในบางกรณีเราต้องการให้เรียกโดยไม่ต้องระบุ label ให้เรากำหนด argument label เป็น `_` แทน เช่น

```swift
func append(_ item: String) {
}

append("Pop")
```

{% hint style="info" %}
ถึงแม้ว่าจะมี label กำกับแต่ละ argument แล้ว เวลาเรียกก็ยังต้องเรียกแต่ละ argument ตามลำดับที่ประกาศ ไม่สามารถสลับได้
{% endhint %}

เราสามารถกำหนด default value ให้กับ argument ได้โดยการกำหนดค่าในตอนประกาศฟังก์ชั่นแบบนี้

```swift
func displayItem(name: String, isDone: Bool = false) {
    print("Item name: \(name), isDone: \(isDone)")
}

displayItem(name: "Learn DDD", isDone: true)
displayItem(name: "Learn iOS")
```

จะเห็นว่าเมื่อเรากำหนด default ให้แล้ว เราสามารถละการส่ง argument นั้นได้ตอนเรียกใช้ฟังก์ชั่น

### ฟังก์ชั่นใน Swift ก็เป็น Type

```swift
func greet(person: String, from hometown: String) -> String {
    return "Hello \(person)! from \(hometown)."
}
```

ฟังก์ชั่นนี้จะมี type เป็นแบบนี้

```swift
(String, String) -> String
```

เนื่องจากฟังก์ชั่นใน Swift เป็น Type เราสามารถประกาศตัวแปรที่มี Type เป็น function ได้ เช่น

```swift
var hello: (String, String) -> String = greet

hello("Pop", "Bangkok")
```

{% hint style="info" %}
การใช้ Function Type มีข้อจำกัดอยู่ตรงที่ Function Type จะไม่สามารถมี Argument label ได้ จากตัวอย่างก่อนหน้า จะเห็นว่าเราเรียก `hello("Pop", "Bangkok")` โดยไม่มีการระบุ argument label สำหรับแต่ละ input
{% endhint %}

และด้วยความที่ฟังก์ชั่นก็เป็น Type ทำให้เราสามารถส่ง ฟังก์ชั่นเป็น input ของฟังก์ชั่นได้ด้วย เช่น

```swift
func download(url: String, completion: (String) -> ()) {
    completion(url)
}

func display(text: String) {
    print(text)
}

download(url: "mock.com", completion:display)
```

รวมทั้งคืนผลลัพธ์เป็นฟังก์ชั่นด้วย แบบนี้

```swift
func greeting(prefix: String) -> (String) -> () {
    func greet(name: String) {
        print("\(prefix) \(name)")
    }
    return greet
}

greeting(prefix: "hello")("Pop")
greeting(prefix: "hello")("John")
```

{% hint style="info" %}
เราสามารถเขียนประกาศฟังก์ชั่นในฟังก์ชั่นได้
{% endhint %}

### Closure

ถ้าอธิบายแบบง่าย ๆ คือ ฟังก์ชั่นคือ closure ที่มีชื่อ หรือก็คือ closure เป็น block ของโค้ดที่ไม่มีการประกาศชื่อนั่นเอง ตัวอย่างเช่น

```swift
func greeting(prefix: String) -> (String) -> () {
    return { name in
        print("\(prefix) \(name)")
    }
}
```

Closure คือส่วนนี้ เนื่องจาก greeting ได้ระบุ Type ของผลลัพธ์ไว้แล้วทำให้ name ใน closure สามารถ infer type เป็น String

```swift
{ name in
    print("\(prefix) \(name)")
}
```

### การลดรูปการเรียกใช้ฟังก์ชั่น ในกรณีที่ input เป็นฟังก์ชั่น

ตัวอย่างเช่น การเรียกฟังก์ชั่น index ของ array เพื่อหา index ของ item แรกที่ตรงกับเงื่อนไขที่ระบุ

ฟังก์ชั่นรับ input เป็นฟังก์ชั่นในการหา โดยวนเรียกฟังก์ชั่นนี้กับทีละ item ใน array โดยที่ถ้า item ไหนทำให้ฟังก์ชั่นที่เป็น input นี้ได้ผลลัพธ์เป็น `true` firstIndex จะให้ผลลัพธ์เป็น Index ของ item นั้น

```swift
items.firstIndex(where: { (item) -> Bool in
    item == "water"
})
```

เริ่มลดรูปจากการตัด `-> Bool` ออก เนื่องจากเรารู้จากฟังก์ชั่น firstIndex แล้วว่าต้องรับ ฟังก์ชั่นที่ return Bool

```swift
items.firstIndex(where: { (item) in
    item == "water"
})
```

ตัด (item) in ออกแทนที่ parameter แรกที่รับ ด้วย `$0`&#x20;

```swift
items.firstIndex(where: { $0 == "water" })
```

ตัด (where: ) ออก parameter สุดท้ายถ้ารับเป็นฟังก์ชั่น สามารถละได้

```swift
items.firstIndex { $0 == "water" }
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pakornpat.gitbook.io/ios-app/v2/swift/function.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
