일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- await
- async
- RN업데이트
- react-native-image-picker
- Hash-table
- javascript
- react
- private-access-to-photos
- react animation
- ios
- hydration mismatch
- react native
- axios
- Swift
- RN아키텍쳐
- named type
- motion.div
- React-Native업데이트
- react-native-permissions
- Throttle
- react-native
- promise.all
- 비동기
- debounce
- no-permission-handler-detected
- animation
- CS
- Promise
- rn
- RN새로운아키텍쳐
- Today
- Total
하루살이 개발일지
[Swift] 함수 본문
Swift에서의 함수의 특징
swift에서의 함수의 특징을 다음과 같이 간단하게 요약할 수 있다.
- 이름이 없는 단순한 C 스타일 함수부터 각 파라미터에 대한 이름과 인수가 있는 복잡한 Objective-C 스타일 메서드까지 다양함
- 모든 함수는 함수의 파라미터 타입과 반환 타입으로 구성된 타입이 있음
- 함수를 파라미터로 다른 함수에 전달할 수 있음
- 함수에서 함수를 반환할 수 있음
- 함수는 다른 함수 내에 작성될 수 있음
- 함수의 파라미터는 기본적으로 상수임 (변수로 사용하려면 `inout` 키워드 사용)
- 외부 매개변수 이름과 내부 매개변수 이름을 구분할 수 있음
- 기본값을 갖는 파라미터를 정의할 수 있음
- 가변 인자(variadic parameter)를 사용해 여러 개의 인수를 받을 수 있음
- 반환 타입이 없을 경우 `Void` 또는 아무것도 반환하지 않음
- 반환값이 여러 개인 경우 튜플을 사용해 반환 가능
함수 정의와 호출
Swift에서 함수를 정의할 때, 입력 값인 파라미터와 반환 값의 타입을 선택적으로 정의할 수 있다. 함수는 작업을 설명하는 이름을 가지고, 호출 시 함수 이름과 인수(argument)를 전달한다. 함수의 인수는 항상 함수의 파라미터 순서와 일치해야 한다.
*인수(argument) : 함수를 호출할 때 함수에 전달되는 실제 값
함수를 정의할 때 특징은 다음과 같다.
- 함수는 `func` 키워드를 사용해 정의
- 모든 함수는 함수의 작업을 설명하는 이름을 가짐
- 함수를 호출할 때는 함수 이름과 파라미터에 해당하는 값을 전달
- 함수의 인수는 파라미터 순서와 일치해야 함
- `return` 키워드를 사용해 값을 반환
예시와 함께 살펴보자.
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}
print(greet(person: "Anna")) // Prints "Hello, Anna!"
print(greet(person: "Brian")) // Prints "Hello, Brian!"
위 예제에서 `greet(person:)` 함수는 String 타입의 파라미터인 person을 받아 인사말을 생성하고 반환한다.
이 함수를 호출할 때 person 인수로 값을 전달하면 해당 값을 포함한 인사말이 반환된다.
함수 파라미터와 반환값
Swift에서 함수 파라미터와 반환값은 매우 유연하다. 이름이 지정되지 않은 단일 파라미터가 있는 간단한 유틸리티 함수부터, 파라미터 이름과 다른 파라미터 옵션이 있는 복잡한 함수까지 다양하게 정의할 수 있다.
파라미터 없는 함수
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld()) // Prints "hello, world"
함수는 파라미터가 없더라도 소괄호 ()가 필요하다. 위 예시에서 sayHelloWorld는 입력 파라미터가 없으며 항상 String 메시지를 반환한다.
여러 개 파라미터가 있는 함수
함수는 소괄호 내 콤마(,)로 여러 개의 입력 파라미터를 가질 수 있다.
func greet(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return greetAgain(person: person)
} else {
return greet(person: person)
}
}
print(greet(person: "Tim", alreadyGreeted: true)) // Prints "Hello again, Tim!"
person이라는 라벨을 가진 String 인수값과 alreadyGreeted 라벨을 가진 Bool 인수값을 콤마로 구분해 greet 함수로 전달해 호출한다.
반환값 없는 함수
함수는 반환 타입의 정의를 요구하지 않는다. 이 경우 함수의 정의는 반환 화살표 (->) 또는 반환 타입을 포함하지 않는다.
func greet(person: String) {
print("Hello, \(person)!")
}
greet(person: "Dave") // Prints "Hello, Dave!"
그러나 함수의 반환값을 정의하지 않아도 여전히 반환값은 존재한다.
반환 타입이 정의되지 않은 함수는 Void 타입의 특별한 값을 반환한다. 이는 () 로 쓰여진 빈 튜플이다.
함수의 반환값은 호출될 때 무시될 수 있는데,
func printAndCount(string: String) -> Int {
print(string)
return string.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world") // prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world") // prints "hello, world" but does not return a value
첫 번째 함수 printAndCount(string:) 은 문자열을 출력하고 문자 개수를 Int로 반환한다.
두 번째 함수 printWithoutCounting(string:)은 첫 번째 함수를 호출하지만 반환값은 무시한다. 두 번째 함수가 호출될 때 첫 번째 함수에 의해 메시지는 출력되지만 반환값은 사용되지 않는다.
Note
반환값은 무시될 수 있지만 함수는 항상 값을 반환한다.
정의된 반환 타입이 있는 함수는 반환되는 값 없이 함수의 바닥에서 빠져나오는 것을 허락하지 않고, 만약 그렇게 할 경우 컴파일 시 에러가 발생한다.
여러 개의 반환값이 있는 함수
여러 개의 값을 반환하기 위해 함수의 반환 타입으로 튜플 타입을 사용할 수 있다.
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)
}
minMax(array:) 함수는 Int 값의 배열에서 가장 작은 값과 가장 큰 값을 포함한 튜플을 반환한다. 이 값들은 함수의 반환값을 조회할 때 이름으로 접근할 수 있도록 min과 max로 라벨되어 있다.
minMax(array:) 함수의 본문은 배열의 첫 번째 정수의 값을 currentMin과 currentMax라 불리는 2개의 변수에 값을 설정하는 것부터 시작한다. 이후 함수는 배열의 나머지 값들을 반복하고, 각 값이 currentMin과 currentMax의 값보다 더 작거나 더 큰지 확인한다. 마지막으로 가장 작고 가장 큰 값은 2개의 Int값인 튜플로 반환된다.
튜플의 멤버 값은 함수의 반환 타입이므로 가장 작은 값과 가장 큰 값을 찾기 위해 점 구문으로 접근할 수 있다.
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)") // Prints "min is -6 and max is 109"
튜플의 멤버 이름은 함수의 반환 타입의 일부로 이미 지정되어 있으므로 함수에서 튜플이 반환되는 시점에 이름을 지정할 필요가 없다.
반환값 없는 함수
함수는 반환 타입 정의를 요구하지 않는다.
func greet(person: String) {
print("Hello, \(person)!")
}
greet(person: "Dave") // Prints "Hello, Dave!"
위 함수는 String 값을 출력하는 greet(person:) 함수이다. 반환값이 필요하지 않기 때문에 함수의 정의는 반환 화살표 (->) 또는 반환 타입을 포함하지 않는다.
하지만 greet(person:) 함수는 반환값을 정의하지 않았지만 여전히 반환값은 존재한다. 반환 타입이 정의되지 않은 함수는 Void 타입의 특별한 값을 반환한다. 이는 ()로 쓰여진 빈 튜플이다. 따라서 함수가 아무 값도 반환하지 않는 것처럼 보이지만, 실제로는 ()를 반환하고 있는 것이다.
한편, 함수의 반환값은 호출될 때 무시될 수 있다.
func printAndCount(string: String) -> Int {
print(string)
return string.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world") // prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world") // prints "hello, world" but does not return a value
함수 printAndCount(string:) 은 문자열을 출력하고 문자 갯수를 Int로 반환한다. 함수 printWithoutCounting(string:) 은 첫번째 함수를 호출하지만 반환값은 무시된다. ( let _ = 구문을 사용하여 반환된 값을 저장하지 않고 버린다.)
즉 Swift에서 함수의 반환값은 반드시 사용해야 하는 것은 아니며, 원하지 않을 경우 무시할 수 있다. 한편, 반환값을 무시하더라도 함수가 호출되면서 발생하는 부수효과(위의 경우는, 콘솔에 문자열을 출력하는 것)는 여전히 발생한다. printWithoutCounting(string:)을 호출하면, printAndCount(string:) 함수에 의해 문자열이 출력되는 것이다.
여러 개의 반환값이 있는 함수
여러 개의 값을 반환하기 위해 함수의 반환 타입으로 튜플 타입을 사용할 수 있다.
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) // 함수 반환 시점
}
minMax(array:) 함수는 Int값의 배열에서 가장 작은 값과 가장 큰 값을 찾는데, 이를 2개의 Int값을 포함한 튜플로 반환한다. 이 값들은 함수의 반환 값을 조회할 때 이름으로 접근할 수 있도록 min과 max로 라벨되어 있다.
즉 함수의 반환 타입을 정의할 때 튜플의 멤버에 이름을 지정하면, 이름을 통해 함수가 반환하는 시점에 별도의 처리를 하지 않아도 직관적으로 값에 접근할 수 있다.
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)") // Prints "min is -6 and max is 109"
여기서 bounds는 (min: Int, max: Int) 타입의 튜플을 참조하고, bounds.min과 bounds.max를 사용해 값에 접근할 수 있다.
함수 인수 라벨과 파라미터 이름
Swift에서 각 함수 파라미터는 인수 라벨과 파라미터 이름을 가진다. 기본적으로 파라미터는 인수 라벨로 파라미터 이름을 사용한다.
- 인수 라벨 : 함수 호출 시 인수 앞에 붙이는 라벨
- 파라미터 이름 : 함수 내부에서 해당 파라미터를 참조할 때 사용하는 이름
func someFunction(firstParameterName: Int, secondParameterName: Int) //파라미터 이름 {
// 함수 본문에서 firstParameterName과 secondParameterName을 사용
}
someFunction(firstParameterName: 1, secondParameterName: 2) //인수 라벨
위 예시에서는, 인수 라벨과 파라미터 이름이 같은 경우이다.
인수 라벨 지정
인수 라벨을 별도로 지정할 수 있다. 이는 공백으로 구분하여 파라미터 이름 앞에 인수 라벨을 작성한다.
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino")) // Prints "Hello Bill! Glad you could visit from Cupertino."
위 예시에서 from은 인수 라벨이다. 이렇게 인수 라벨을 사용하면 의도가 명확한 함수 본문을 사용할 수 있다.
인수 라벨 생략
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// 함수 본문
}
someFunction(1, secondParameterName: 2)
인수 라벨을 생략하고 싶으면 언더바(_)를 사용할 수 있다. 파라미터가 인수 라벨을 가지고 있다면 함수를 호출할 때 인수는 반드시 라벨을 지정해야 한다.
파라미터 기본값
파라미터의 타입 뒤에 값을 할당하여 기본값을 정의할 수 있다.
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// parameterWithDefault는 기본값 12를 가집니다.
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault는 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault는 12
기본값이 없는 파라미터는 일반적으로 함수의 의미에서 더 중요하므로, 함수의 파라미터 리스트 시작부분에 위치한다.
가변 파라미터
가변 파라미터는 0개 이상의 특정 타입의 값을 허용한다. 함수가 호출될 때 여러 개의 입력값이 전달될 수 있는 특정 파라미터는 가변 파라미터를 사용한다. 파라미터 타입 뒤에 '...'를 추가하여 작성한다.
가변 파라미터에 전달된 값은 함수 본문 내에서 적절한 타입의 배열로 사용할 수 있는데, 아래 예시에서 numbers라는 이름과 Double... 타입을 가진 가변 파라미터는 함수 본문 내에서 [Double] 타입의 numbers라 불리는 상수 배열로 사용할 수 있다.
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5) // 3.0 반환
arithmeticMean(3, 8.25, 18.75) // 10.0 반환
함수는 여러 개의 가변 파라미터를 가질 수 있는데, 가변 파라미터 뒤에 오는 첫 번째 파라미터는 인수 라벨을 가져야 한다. 인수 라벨은 가변 파라미터에 전달되는 인수와 가변 파라미터 뒤에 오는 파라미터에 전달되는 인수를 명확하게 한다.
func mixedParameters(numbers: Int..., and message: String) {
for number in numbers {
print(number)
}
print(message)
}
mixedParameters(numbers: 1, 2, 3, and: "End of numbers")
// 1
// 2
// 3
// End of numbers
위처럼, numbers: Int... 가변 파라미터 뒤에 인수 라벨 and를 가지는 첫 번째 파라미터가 와야 한다.
In-Out 파라미터
in-out 파라미터는 함수 내에서 파라미터 값을 변경하고, 그 변경된 값을 함수 호출이 종료된 후에도 유지하고 싶을 때 사용한다. 기본적으로 함수 파라미터는 상수이므로 함수 내에서 값을 변경할 수 없다. (컴파일 타입 에러 발생) -> in-out 파라미터를 사용하면 이를 변경할 수 있다.
- in-out 파라미터는 'inout' 키워드를 사용하여 정의한다.
- 함수에 in-out 파라미터를 전달할 때는 변수이름 앞에 앰퍼샌드(&)를 붙인다.
- in-out 파라미터의 인수로 변수만 전달할 수 있다. (상수와 반복은 수정할 수 없기 때문)
- in-out 파라미터는 기본값을 가질 수 없고 가변 파라미터는 inout으로 표기할 수 없다.
아래 예제는 기본 함수 파라미터의 동작을 보여주는 예시이다.
func modifyValue(_ a: Int) {
var a = a
a = 20
}
var myValue = 10
modifyValue(myValue)
print(myValue) // 10 출력
기본적으로 함수의 파라미터는 상수로 처리되므로, 함수가 호출될 때 전달된 값의 복사본이 함수로 전달된다. 즉 함수 내에서 파라미터 값을 변경하더라도 함수 호출이 끝나면 원래 변수의 값은 변하지 않는 것이다.
위 예시에서 myValue는 modifyValue 함수에 전달되지만, 함수 내에서 a의 값을 변경해도 myValue의 값은 변경되지 않는다. 이는 함수에 전달된 값의 복사본을 사용하기 때문이다.
반면 아래 예제는 inout 파라미터를 사용해 함수가 전달된 변수의 실제 값을 변경한다.
func modifyValue(_ a: inout Int) {
a = 20
}
var myValue = 10
modifyValue(&myValue)
print(myValue) // 20 출력
modifyValue 함수는 inout 키워드를 사용하여 정의되었고, myValue를 &를 사용해 전달한다. 결과적으로 함수 내에서 a를 변경하면 실제로 myValue가 변경된다.
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"
위 예시에서는 someInt와 anotherInt의 기본값이 함수 바깥에서 정의되었지만 swapTwoInts(_:_:) 함수로 인해 원래 값이 수정되는 것을 보여준다. 즉 in-out 파라미터는 함수가 함수 본문의 범위를 벗어나 영향을 미치는 허나의 방법이다.
함수 타입
모든 함수는 파라미터 타입과 반환 타입으로 구성된 특정 함수 타입을 가진다.
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
위 함수의 타입은 (Int, Int) -> Int 이다.
이는 이렇게 읽을 수 있다 -> "함수는 모두 Int 타입인 2개의 파라미터를 가지며 Int 타입을 반환한다."
func printHelloWorld() {
print("hello, world")
}
이렇게 파라미터 또는 반환 값이 없는 함수도 있다. 이 함수의 타입은 () -> Void 이다.
함수 타입 사용
함수 타입을 변수에 저장할 수 있다.
var mathFunction: (Int, Int) -> Int = addTwoInts
여기서 mathFunction 변수는 (Int, Int) -> Int 타입을 가지며, addTwoInts 함수를 참조한다.
그 변수를 통해 함수를 호출할 수 있다.
print("Result: \(mathFunction(2, 3))") // Prints "Result: 5"
mathFunction(2, 3)은 addTwoInts(2, 3)과 동일하게 동작한다.
변수에 같은 함수 타입을 가지는 다른 함수를 할당할 수 있다.
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))") // Prints "Result: 6"
mathFunction은 multiplyTwoInts 함수를 참조하는데, mathFunction(2, 3)은 multiplyTwoInts(2, 3)과 동일하게 동작한다.
파라미터 타입으로 함수 타입
함수 타입을 다른 함수의 파라미터로 사용할 수 있다.
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5) // Prints "Result: 8"
함수 printMathResout는 (Int, Int) -> Int 타입의 함수를 파라미터로 받아 이를 호출하고 결과를 출력한다.
반환 타입으로 함수 타입
함수의 반환 타입으로 함수 타입을 사용할 수 있다. 반환하는 함수의 반환 화살표 (->) 바로 뒤에 완전한 함수 타입을 작성하면 된다.
다음은 함수 타입을 반환 타입으로 사용하는 예시이다.
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero는 이제 stepBackward 함수를 참조합니다.
print("Counting to zero:")
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
위 예제에서 stepForward와 stepBackward 함수의 타입은 (Int) -> Int이다.
chooseStepFunction 함수는 Bool 타입의 backward 파라미터를 받는데, 반환 타입은 (Int) -> Int이다. (반환되는 함수는 stepBackward나 stepForward 중 하나기 때문)
이후 chooseStepFunction(backward:) 함수를 호출하여 currentValue > 0 조건에 따라 stepBackWard 함수가 반환되게 되고, 반환된 함수는 moveNearerToZero에 저장되고 이를 사용해 currentValue를 0으로 만든다.
중첩 함수
중첩 함수(nested functions)는 다른 함수 내에 정의된 함수이다.
중첩 함수는 기본적으로 바깥에서 보이지 않으며 중첩 함수를 둘러싼 함수 내부에서만 호출할 수 있다. 중첩 함수를 둘러싼 함수는 중첩 함수 중 하나를 반환하여 중첩 함수를 다른 범위에서 사용할 수도 있다.
아래 예씨는 중첩 함수를 사용해 두 숫자의 합과 차를 계산하는 함수이다.
func calculate(operation: String) -> (Int, Int) -> Int {
// 중첩 함수 정의
func add(a: Int, b: Int) -> Int {
return a + b
}
func subtract(a: Int, b: Int) -> Int {
return a - b
}
// operation 값에 따라 적절한 함수를 반환
if operation == "add" {
return add
} else {
return subtract
}
}
// 함수를 호출하여 사용할 수 있는 예시
let addFunction = calculate(operation: "add")
let subtractFunction = calculate(operation: "subtract")
let sum = addFunction(3, 5) // 8
let difference = subtractFunction(10, 4) // 6
print("Sum: \(sum), Difference: \(difference)")
calculate(operation:) 함수는 두 개의 중첩 함수를 정의한다.
- add(a:b:) : 두 숫자의 합을 반환하는 함수
- subtract(a:b:) : 두 숫자의 차를 반환하는 함수
calculate(operation:) 함수는 전달된 operation 값에 따라 add 또는 subtract 함수를 반환한다. 반환된 함수는 addFunction과 subtractFunction 변수에 저장되는데,
- addFunction(3, 5)는 3과 5의 합인 8을 반환한다
- subtractFunction(10, 4)는 10과 4의 차인 6을 반환한다
이렇게 중첩 함수는 외부에서 보이지 않지만 둘러싼 함수 내부에서 유용하게 사용할 수 있다. 또한 적절한 함수를 반환해 다른 범위에서도 사용할 수 있다.
'앱개발 > Swift' 카테고리의 다른 글
Swift에서의 기본 데이터 타입 (0) | 2024.05.30 |
---|---|
Swift란? Swift에서의 변수, 상수, 정적 변수 (1) | 2024.05.30 |