[Swift] Day5 - functions, parameters, and errors

한철희·2023년 2월 24일
0

100 DaysOfSwift

목록 보기
1/11
post-thumbnail

velog로 옮기고 처음 쓰는 글이네요
이전의 Day1 ~ Day4는 네이버블로그에 있습니다.
(https://blog.naver.com/myhan601)
그럼 시작해볼까요?


Writing functions

Funtions(함수)는 일정 코드를 재사용할 수 있게 해줍니다. 때문에 함수를 한 번 작성하면 많은 곳에서 사용할 수 있게 됩니다.
일반적으로 코드를 반복하는 것은 좋지 않고, 함수가 그런 상황들을 피하게 해줌다
Swift에서 함수는 func키워드를 사용해 아래와 같이 작성 가능합니다

func 함수이름() {
	내부코드
}

예시로 앱 사용중에 정보를 알려주는 함수를 작성해볼게요

func printHelp() {
    let message = """
Welcome to MyApp!

Run this app inside a directory of images and
MyApp will resize them all into thumbnails
"""
    print(message)
}

작성한 함수를 사용하려면 어떻게 해야할까요?
바로 함수를 호출해주면 됩니다

printHelp()

이런식으로 말이죠
아래는 실행한 결과입니다


Accepting parameters

함수는 내가 사용할 때 마다 커스텀할 수 있으면 더 강력한 도구가 됨다
무슨말이냐면 print()함수를 생각하면 편합니다

print("Hello, world!")

print라는 함수를 사용할 때 srting값을 전해주죠?
마찬가지로 Swift에서는 함수 내부에서 사용되는 값을 전해줌으로서 작동되는 방식을 바꿀 수 있어요
이런 값들을 parameter 라고 합니다
파라미터를 수용할 수 있는 함수를 만드려면 파라미터에 이름을 붙여주면 됩니다
그리고 swift니까 물론 타입도 지정해줘야겠죠
예시로 숫자를 제곱하는 함수를 보여드릴게요

func square(number: Int) {
	print(number * number)
}

위 함수에서 유추할 수 있는 것은 Int 파라미터를 줘야한다는 것과
파라미터의 이름이 number라는 것이네요
그리고 함수를 사용할 때는 아래와 같이 해주면됩니다

square(number: 8)


실행 결과임다


Returning values

데이터를 받을 수 있으면 돌려줄 수 도 있겠죠?
파라미터 옆에 문구를 추가해주면 됩니다

func square(number: Int) -> Int {
	return number * number
}

아까랑 좀 달라졌죠? -> 옆의 Int 는 반환될 값의 타입을 의미합니다
그리고 return 도 추가되었는데 반환할 값이 있으면 반환하고 함수를 종료하는 역할을 합니다
그리고 함수 결과를 바로 출력하지 않고 값으로 반환하기 때문에 아래처럼 활용할 수 있습니다

let result = square(number: 8)
print(result)

반환된 값을 result라는 상수에 할당해주고
result를 출력하는 코드입니다
아래는 실제 실행 결과입니다.


Parameter labels

우리는 squre()함수를 이렇게 작성했죠

func square(number: Int) -> Int {
	return number * number
}

여기선 파라미터를 number라고 이름을 붙였죠
그래서 함수안에서도 사용할 수 있습니다
그리고 함수를 호출하여 사용할때도 이름을 써야하죠

let result = square(number: 8)

Swift에서는 파라미터에 이름을 2개 사용할 수 있도록 해줘요
1. 외부에서 함수를 호출할때 쓰는 것
2. 함수 내부에서 쓰는 것
요렇게 2개 입니다. 보통 이름을 작성하듯이하고 스페이스바로 구분합니다

func sayHello(to name: String) {
	print("Hello, \(name)!")
}

여기서 파라미터는 'to name' 입니다. 외부에서는 'to'로 불리고
내부에서는 'name'으로 사용되죠
이런식으로 사용하면 호출할 때 좀더 자연스럽게 읽히고
함수 내부에서 어디에 쓰이는 것인지 좀더 명확해지는 효과가 있답니다

sayHello(to: "Taylor")


Omitting parameter labels

그러고보니 print()함수는 사용할 때 파라미터를 쓴적이없죠?
보통 print("Hello") 로 작성하지 print(message: "Hello") 를 쓰진 않죠

이 방법을 쓰고싶다면 외부 파라미터 이름에 '_' 를 사용하면 됩니다.

func greet(_ person: String) {
	print("Hello, \(person)!")
}

그런뒤에 greet()를 파라미터없이 호출할 수 있습니다

greet("Taylor")

이렇게하면 몇몇 상황에서 자연스럽게 읽게되는 장점이 있지만 보통은 파라미터 이름을 작성하기를 권합니다. 혼란스럽지 않게하기 위해서요
예를들어,

setAlarm(5)

이렇게 작성하면 5시에 작동하는건지, 5분뒤인건지, 5시간 뒤인지 알기 힘들죠?
이런 혼란을 피하기 위해 명확히 작성해줄 필요가 있습니다


Default parameters

print()함수는 화면에 뭔가를 출력하죠. 근데 항상 출력 후 다음 줄로 넘어갑니다. 그래서 여러번 출력하면 같은 줄에 출력되는 일이 없죠

보통의 경우 사람들은 새로운 줄에 쓰는 것을 원했기 때문에 print() 함수에 terminator라는 파라미터에 새로운 줄 쓰기를 기본값으로 가진다고 하네요
이건 처음알았네

위 내용에서 보듯이 함수 파라미터에 default value(기본값) 을 줄 수 있어요
'='만 써주면 됩니다. 위에서 작성했던 greet() 함수를 다시 작성해볼까요?

func greet(_ person: String, nicely: Bool = true) {
	if nicely == true {
    	print("Hello, \(person)!")
    } else {
    	print("Oh no, it's \(person) again...")
    }
}

nicely 라는 파라미터에 '= true' 라는 구문을 추가해줬습니다
이제 nicely파라미터는 true를 기본 값으로 가지겠네요

greet("Taylor")
greet("Taylor", nicely: false)

첫번째 줄의 Taylor는 "Hello, Taylor"가 출력되겠네요
nicelytrue니까요
두번째 줄은 "Oh no, it's Taylor again..." 이 출력될겁니다
함수를 호출하면서 nicely 파라미터에 false 값을 넣었기 때문이죠

실제로 그런지도 확인해 봤습니다


Variadic functions

몇 함수들은 가변적인데요 같은 타입이라면 다수의 파라미터를 받을 수 있습니다.
print() 함수도 포함됩니다

print("바밤바", "밤이 들어있는", "바밤바")

이렇게 작성하면 한 줄에 모두 출력합니다. 공백으로 구분하구요
가변인자라고도 하는데요 '...' 를 추가하면 사용할 수 있어요
Int 는 한개의 파라미터만 받지만 Int... 는 수십,수백개까지도 된다고 합니다

그리고 함수에서는 swift가 배열로 변환해주기 때문에 원한다면 반복문을 사용할 수도 있습니다

func square(numbers:Int...) {
	for number in numbers {
    	print("\(number) squared is \(number * number)")
    }
}

호출할 때는 콤마로 구분해서 여러개의 파라미터를 넘겨줍니다

square(numbers: 1, 2, 3, 4, 5)

실제로 어떻게 작동하는지 볼까요?

따-란


Writing throwing functions

입력값이 좋지 않거나 내부적으로 잘못되면 함수는 작동하지 않기도 합니다
Swift는 throws라는 키워드를 통해 에러를 확인할 수 있게 해줍니다

throws를 사용하기 전에 enum을 통해 몇가지를 설정해줘야합니다.
Swift에 존재하는 Error type에 기반해서요
패스워드가 올바른지 확인하는 함수를 작성해 봅시다

enum PasswordError: Error {
	case obvious
}

우선 enum을 통해서 어떤 Error 를 검출할지 설정하구요
그리고 checkPassword() 라는 함수를 작성할 건데요 뭔가 잘못되면 error를 throw할겁니다. throws키워드는 반환값을 나타내는 화살표 전에 작성합니다.
그리고 PasswordError.obvious를 통해 password를 "password"로 할 경우 에러를 반환합니다

func chechPassword(_ password: String) throws -> Bool {
	if password == "password" {
    	throw PasswordError.obvious
    }
    
    return true
 }

실제로 throw가 작동되었는데요 catch하는 부분이 없어서 에러가 떴네요


Running throwing functions

Swift는 프로그램을 실행할 때 에러가 발생하는 것을 싫어합니다.
뭔말이냐면 error-throwing 기능을 우연히 사용하지 못하게합니다
뭔 소리냐...

대신에 세가지 키워드를 통해서 사용할 수 있습니다.

do {
	try checkPassword("password")
    print("That password is good!")
} catch {
	print("You can't use that password.")
}

do 블록안에는 문제가 될만한 함수를 포함하구요
try는 실행되는 함수앞에 작성해줍니다
catch는 에러가 발생했을시 작동하는 부분이구요

do 블록안에 에러가 thrown되면 그 즉시 catch블록으로 넘어가서 실행된다.
실제로 에러가 발생했기 때문에 "You can't use that password."가 출력됩니다. catch구문을 바로 실행히켰기 때문에 "That password is good!" 구문은 실행되지 않죠

실제 앱을 개발하면 자주 사용할 것 같은데 나중에 이것만 따로 다뤄보겠습니다.


inout parameters

Swift 함수에 넘겨지는 모든 파라미터는 상수임다. 그래서 변경할 수 없죠
만약 바꾸고 싶다면 하나 혹은 그 이상의 파라미터를 inout으로 넘겨야합니다.
그렇게 하면 함수내부에서 값이 바뀌고 이런 변화가 함수 밖의 원래 값에도 변화를 줍니다.

예를 들어 어떤 숫자를 2배 계산하고 싶으면 새로 반환하는것보다 바로 값을 바꿔버리는게 편할겁니다.

func doubleInPlace(number: inout Int) {
	number *= 2
}

위처럼 작성하면 됩니다. inout 키워드는 파라미터 타입앞에 작성하구요

이 키워드를 사용하려면 Int가 변수여야합니다. 상수에는 inout을 사용할 수 없어요.
그리고 함수 호출하면서 값을 넘겨줄때 '&' 를 붙여줘야합니다
이 기호가 inout를 사용한다는 표식?이 됩니다

var myNum = 10
doubleInPlace(number: &myNum)

그리고 실제로 실행하면 10 이었던 myNum 변수가 함수 호출 후 20으로
변경된걸 확인할 수 있네요.


Summary
1. 함수는 우리가 반복적으로 작성하지 않아도 코드를 재사용할 수 있게 해준다
2. 함수는 파라미터를 받는다. 파라미터의 타입만 잘 명시해놓자
3. 함수는 값을 반환한다. 반환받는 값의 타입도 명시해놓자. 만약 여러 값을 받고 싶으면 튜플을 쓰면된다.
4. 함수의 파라미터에 외부, 내부용의 다른 이름을 쓸 수 있다. 혹은 외부 이름을 생략할수도 있다.
5. 파라미터는 기본값을 가질 수 있다. 특정 값을 기본으로 해놓으면 코드 작성량을 줄일 수 있습니다
6. 가변인자는 여러개의 파라미터를 받을 수 있다. Swift가 배열로 변환해줍니다
7. 함수는 에러를 throw할 수 있어요. 하지만 try와 catch를 꼭 작성해야합니다
8. inout을 사용해서 함수 내부의 변수를 바꿀 수 있다. 그러나 새로운 값을 반환하는게 보통은 더 좋은 방법이다

profile
초보 개발자 살아남기

0개의 댓글