Swift: تعريف دوال Swift والوسائط: من المبتدئ إلى المتقدم
Functions are the fundamental building blocks of code in Swift. This lesson teaches you how to define functions and use every parameter form flexibly, making your code more semantic and reusable.
1. What You'll Learn
- Define and call functions using the
funckeyword - Understand the difference between argument labels and parameter names
- Set default values for parameters
- Use
inoutfor in-place parameter mutation - Handle a variable number of arguments with variadic parameters
2. A Backend Engineer's Real Story
(1) Pain: Unclear parameter meaning at the call site
Bob is developing an e-commerce order system. He wrote a function to calculate the total order price:
func calculate(price: Double, count: Int, rate: Double) -> Double {
return price * Double(count) * (1 - rate)
}
// At the call site — parameter meaning is guesswork
let result = calculate(price: 100, count: 3, rate: 0.1)
The team split over what rate: 0.1 meant — some thought it was a 10% tax, others thought it was a 10% discount. The function signature didn't express the semantic role of each parameter.
(2) The Argument Label Solution
Swift lets you define both an external label and an internal name for each parameter, making the call site read like natural language:
func calculate(price: Double, count: Int, discount rate: Double) -> Double {
return price * Double(count) * (1 - rate)
}
// Call site is clear: "discount" tells you it's a discount rate
let result = calculate(price: 100, count: 3, discount: 0.1)
(3) Result: Semantically clear function calls
| Dimension | Before | After |
|---|---|---|
| Parameter meaning | Pure guesswork | Understandable at the call site |
| Code readability | Must jump to definition | Meaning clear in one line |
| Team communication | Frequent debates over meaning | Self-documenting function signature |
| Maintenance efficiency | Global search on parameter changes | Local changes, no ambiguity |
3. Basic Function Definition
A function is a reusable block of code in Swift, defined with the func keyword.
graph LR
A[func keyword] --> B[Function name]
B --> C[Parameter list]
C --> D[Return arrow & type]
D --> E[Function body]
A --> F["func greet(name: String) -> String { return \"Hello \\(name)\" }"]
| Component | Required | Notes |
|---|---|---|
func keyword |
Yes | Marks a function declaration |
| Function name | Yes | Identifies the function, use camelCase |
Parameter list () |
Yes | Empty parentheses even with no parameters |
Return -> Type |
No | Omit to return Void |
Body {} |
Yes | The code block executed by the function |
(1) No Parameters, No Return Value
func sayHello() {
print("Hello!")
}
sayHello() // Call
Output:
TEXT 📖 للعرض فقطHello!
(2) Parameters and Return Values
func add(a: Int, b: Int) -> Int {
return a + b
}
let sum = add(a: 5, b: 3)
print("5 + 3 = \(sum)")
Output:
TEXT 📖 للعرض فقط5 + 3 = 8
▶ Example: Order Amount Calculation
// ============================================
// Calculate order total including tax
// ============================================
func orderAmount(price: Double, quantity: Int) -> Double {
return price * Double(quantity)
}
let amount = orderAmount(price: 29.99, quantity: 3)
print("Order amount: $\(amount)")
Output:
TEXT 📖 للعرض فقطOrder amount: $89.97
4. Argument Labels and Default Values
(1) Argument Labels
Swift lets you specify an external label (used at the call site) and an internal name (used inside the function body) for each parameter:
| Style | Syntax | Call Site | When to Use |
|---|---|---|---|
| Label = name | func foo(name: String) |
foo(name: ...) |
Parameter name is semantic enough |
| External label | func foo(with name: String) |
foo(with: ...) |
Call reads like natural language |
| Omit label | func foo(_ name: String) |
foo(...) |
Verb already expresses the parameter |
| Combinations | Varying labels | Flexible | Custom requirements |
▶ Example: Comparing Label Styles
// ============================================
// Three argument label styles compared
// ============================================
// 1. Default — label equals name
func greet1(name: String) {
print("Hello, \(name)")
}
// 2. Custom external label
func greet2(to name: String) {
print("Hello, \(name)")
}
// 3. Omit external label (underscore)
func greet3(_ name: String) {
print("Hello, \(name)")
}
greet1(name: "Alice")
greet2(to: "Bob")
greet3("Charlie")
Output:
TEXT 📖 للعرض فقطHello, Alice Hello, Bob Hello, Charlie
(2) Default Parameter Values
When you provide a default value for a parameter, callers can omit that argument:
func makeCoffee(size: String, sugar: Int = 1) -> String {
return "\(size) coffee with \(sugar) sugar(s)"
}
print(makeCoffee(size: "Large")) // Uses default sugar
print(makeCoffee(size: "Medium", sugar: 0)) // Custom sugar
Output:
TEXT 📖 للعرض فقطLarge coffee with 1 sugar(s) Medium coffee with 0 sugar(s)💡 Tip: Place default parameters at the end of the parameter list to avoid ambiguity at call sites.
5. Variadic Parameters and inout
(1) Variadic Parameters
A variadic parameter accepts zero or more values of a given type and is available as an array inside the function body:
func sum(_ numbers: Double...) -> Double {
var total = 0.0
for number in numbers {
total += number
}
return total
}
print(sum(1, 2, 3)) // 3 arguments
print(sum(10, 20)) // 2 arguments
print(sum()) // 0 arguments
Output:
TEXT 📖 للعرض فقط6.0 30.0 0.0
| Trait | Description |
|---|---|
| Syntax | Add ... after the type |
| Count | 0 to any number |
| Type | All values must be the same type |
| Position | At most one per function; should be the last parameter |
(2) inout Parameters
An inout parameter lets a function modify the caller's variable — essentially pass-by-reference rather than by copy:
// ============================================
// inout parameter: swapping two variables
// ============================================
func swapValues(_ a: inout Int, _ b: inout Int) {
let temp = a
a = b
b = temp
}
var x = 10
var y = 20
swapValues(&x, &y)
print("x = \(x), y = \(y)")
Output:
TEXT 📖 للعرض فقطx = 20, y = 10⚠️ Note: Prefix the variable with
&when passing to aninoutparameter. You cannot pass constants or literals.
▶ Example: Universal Average Calculator
// ============================================
// Variadic + inout combined: compute average and track calls
// ============================================
func average(_ scores: Double..., record callCount: inout Int) -> Double {
callCount += 1
guard !scores.isEmpty else { return 0 }
var total = 0.0
for score in scores {
total += score
}
return total / Double(scores.count)
}
var callTimes = 0
print("Average: \(average(85, 90, 78, record: &callTimes))")
print("Average: \(average(100, 95, record: &callTimes))")
print("Function called \(callTimes) times")
Output:
TEXT 📖 للعرض فقطAverage: 84.33333333333333 Average: 97.5 Function called 2 times
6. Full Example: Order Discount Calculator
// ============================================
// Full example: Order discount calculator
// Combines argument labels, defaults, variadic, inout
// ============================================
import Foundation
// 1. Compute subtotal (variadic)
func subtotal(_ prices: Double...) -> Double {
var total = 0.0
for price in prices {
total += price
}
return total
}
// 2. Apply discount (default parameter + argument label)
func applyDiscount(to total: Double, rate: Double = 0.1) -> Double {
return total * (1 - rate)
}
// 3. Log orders (inout parameter)
func logOrder(_ description: String, counter: inout Int) {
counter += 1
print("[\(counter)] \(description)")
}
// 4. Simulate order processing
var orderCount = 0
let item1 = subtotal(29.99, 49.99)
let item2 = subtotal(9.99, 14.99, 24.99)
logOrder("Item 1 subtotal: $\(item1)", counter: &orderCount)
logOrder("Item 2 subtotal: $\(item2)", counter: &orderCount)
let total1 = applyDiscount(to: item1, rate: 0.15)
let total2 = applyDiscount(to: item2)
let finalTotal = total1 + total2
logOrder("Final total: $\(finalTotal)", counter: &orderCount)
Output:
TEXT 📖 للعرض فقط[1] Item 1 subtotal: $79.98 [2] Item 2 subtotal: $49.97 [3] Final total: $112.94
❓ FAQ
[1, 2, 3] form. Variadic is more concise.-> Type is equivalent to returning Void (the empty tuple ()). The function body can omit the return statement. For example, func log() { print("log") } returns Void.📖 Summary
- Functions are defined with the
funckeyword; the parameter list and body form the basic structure - Argument labels make function calls read more like natural language — design appropriate external labels for every parameter
- Default parameter values reduce repetitive call code and should go at the end of the parameter list
- Variadic parameters
...accept zero or more values of the same type, exposed as an array inside the body - inout parameters enable pass-by-reference to modify caller variables; prefix with
&at the call site
📝 Exercises
- Beginner: Write a
greetfunction that acceptsname(String) andgreeting(String, default "Hello") and prints a greeting. Call it at least twice using two different argument label styles. - Intermediate: Write a
calculateBMIfunction that acceptsweight(kg, Double) andheight(m, Double), returning the BMI value. Use argument labels so the call site reads likecalculateBMI(weight: 75, height: 1.8). Also add aninoutparameter to track the number of calls. - Challenge: Write a
gradesAnalyzerfunction that uses variadic parameters to accept any number of scores and returns the highest, lowest, and average scores. Use aninoutparameter to maintain an analysis history (append the count of each analysis to an array). Print the history at the end.