일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 직선의방정식
- 이분그래프
- 아이엔이야기
- 숫타니파아타
- 최단경로문제
- 오블완
- 2023채용박람회
- 나르시스트
- 배윤슬
- 청년도배사 이야기
- wxmaxima
- 집착형
- kgol
- 다자녀장학금
- 무소의뿔
- 그래프2
- 쌍대성원리
- 티스토리챌린지
- 정보처리기사공부방법
- 합의정리
- 데이터베이스시스템
- 이런 사람에게 "절대" 돈과 시간 쓰지 마세요. (이헌주 교수 3부)
- 오일러투어
- 맥북에서 wxMaxima 설치
- 윤파고
- wxMaxima install for mac os
- 등록금0원
- 허스켈그래프
- playground배열
- 제거된값 첨부하기
- Today
- Total
사적공간
Swift 함수 본문
출처 :꼼꼼한 재은씨의 swift 문법/이재은/루미페이퍼
입력값 == 인자값 == 파라미터
결과값 == 반환값 == 리턴값
1) 일반함수
2) 사용자정의 함수
함수의 이름의 시작은 반드시 영어 또는 언더바_ 로 시작해야 함.
함수의 호출
함수 정의시 매개변수 명 = 함수 호출시 인자 레이블
(인자레이블로 역할을 하지 않는 매개변수도 있기 때문에 별개로 봐야 함. )
함수 인자레이블은 호출, 함수식별에 쓰임.
함수이름 규칙
함수 정의 | 함수명 (함수 식별자로 보는게 타당) |
func incrementBy( ) | incrementBy( ) |
func incrementBy(amount: Int, numberOfTime: Int ) | incrementBy(amount: numberOfTime:) |
스위프트에서 함수 호출은 ' 함수명 + 괄호 + 인자값 ' 이다.
함수의 반환값과 튜플
함수는 하나의 값만을 반환해야 하지만 집단 자료형(딕셔너리, 배열, 튜플.. 구조체, 클래스)을 이용해 여러 값을 반환할 수 있음
그 중 튜플
튜플형태의 정의, 반환값을 튜플로 정의함
튜플복습
이름이 길거나 사용하기 복잡한 타입을 축약시키는 타입 알리어스를 쓸 수 있음
타입만 가능, 구체적인 값은 불가
typealias <새로운 타입 이름> = <타입 표현>
매개변수
내부 매개변수 : 함수가 내부적으로 인자값을 참조하기 위해 사용하는 변수
외부 매개변수 : 함수 외부에서 함수나 인자값을 구분하기 위해 사용하는 변수 (인자레이블 역할을 함)
cf) 내부 외부 매개변수를 구분하지 않으면 그냥 매개변수가 인자레이블 역할을 했음
func 함수이름( <외부 매개변수명> <내부 매개변수명>:<타입>, <외부 매개변수명><내부 매개변수명>:<타입>.. ) {
// 함수가 작성되는 곳
}
호출은
함수이름(<외부 매개변수명>:<외부 매개변수명>:)
생략은 언더바로 가능
func 함수이름( _<내부 매개변수명>:<타입>, _ <내부 매개변수명>:<타입>.. )
가변인자
가변적인 개수의 인자값을 입력받아 처리해야 할 때 쓰는 형식이 존재함.
매개변수 타입 다음에 ...연산자를 써줌.
func 함수이름(매개변수명: 매개변수 타입 ...)
기본값을 갖는 매개변수
기본값이 있는 함수는 호출시 인자값을 생략하거나, 기본값으로 입력된 값 말고 다른 값으로 새로 입력하여 호출할 수 있다.
func 함수이름(매개변수: 매개변수타입 = 기본값) {
실행할 내용
}
매개변수의 수정
매개변수는 실질적으로 상수임. 함수 내부에서 수정이 불가함.
-> 근데 이걸 가능하게 할 수 있음 매개변수를 변수처럼 쓸 수 있는 방법은 함수내부에 매개변수와 동일하 이름의 변수를 정의해서 쓰면 됨.
InOut 매개변수
swift에서 InOut 키워드는 call by reference 기능을 위한 도구
함수 외부에서 정의된 값을 함수에서 사용할 때, 값을 복사하여 가져가기 때문에(call by value) 기존의 있던 값과 함수가 가져간 값은 별개의 값임. (함수 내부의 변수 연산이 함수 외부의 변수에 영향을 미치지 못함)
매개변수 인자값 앞에 InOut 키워드를 써주면 매개변수로 가져오려는 값이 저장된 주소를 가져오게 됨. 그리고 호출시 함수 외부에 값이 저장된 변수명 앞에 주소 추출 연산자 & 를 붙임.
값에 의한 전달과 참조에 의한 전달
예외적으로 클래스로 구현된 인스턴스는 inOut 사용하지 않아도 항상 참조에 의해 전달됨. 주의해야 함.
inOut 키워드가 붙은 매개변수에 인자값을 입력할 떄는 인자값 종류에 주의해야 함. 함수 내부에서 원본 객체에 직접 값을 수정할 수 있어야 하므로 상수는 전달 대상이 될 수 없음. 같은 이유로 리터럴도 전달 대상이 안됨.
변수범위의 특성을 이용하여 inOut 키워드를 쓰지 않고 참조에 의한 전달과 같은 효과를 가질 수 있음. 상위 범위에서 정의된 변수는 하위 범위에서도 사용할 수 있는데, 하위 범위의 함수에서 상위범위의 값을 가져가 수정하면 상위 범위에도 그대로 반영됨. 참조형식으로 전달하기 때문임.
{
상위범위
{
하위범위
}
}
변수의 생존 범위와 생명 주기
변수나 상수는 정의된 위치에 따라 생존할 수 있는 범위를 부여받는데 이것을 스코프(Scope) 라고 함.
글로벌(Global) 변수 == 전역변수 : 프로그램 모든 곳에서 참조 가능하며 특별한 경우 제외하고 삭제 안됨
로컬(Local) 변수 == 지역변수 : 특정 범위 내에서만 참조 및 사용 가능 , 조건절이나 함수 구문 등 특정 실행 블록 내부에서 선언된 것들이며, 선언된 블록 내부에서만 참조 가능. 지역변수는 선언된 블록의 실행과 함께 생성되었다가 소멸됨. 이것을 변수의 생명주기(Life Cycle) 이라고 함.
생성된 블록이 아닌 다른 블록에서 변수가 쓰일 경우, 변수는 반드시 초기화(=메모리를 할당받음)를 해야하는데, 이유는 하나의 블록에서 다른 블록으로 참조에 의한 전달 과정이 일어나기 때문임. 변수의 주소값이 필요함.(메모리를 할당받아야 주소가 있으니까)
-하위범위에서 정의한 변수를 상위범위에서 연산할 수 없음.
-상위범위에서 정의된 변수가 하위범위에서 사용될 때는 값이 참조 방식으로 전달 됨 그래서 블록내부 값을 전달하면 외부에도 그래도 적용.
-상위범위와 하위범위에 각각 정의된 변수는 그 범위에서만 연산되며. 결과값도 범위에 따라 제각각임.
블록 내부에 변수나 상수가 사용될 경우, 컴파일러는 이 변수가 정의된 위치를 다음의 순서에 따라 검색함.
1. 함수 내부에서 정의된 변수를 찾음. |
2. 함수 외부에서 정의된 변수를 찾음. |
3. 글로벌 범위에서 정의된 변수를 찾음. |
4. import 된 라이브러리 범위에서 찾음. |
일급 객체(First Class Function)로서의 함수
1. 객체가 런타임에도 생성이 가능해야 한다.
2. 인자값으로 객체를 전달할 수 있어야 한다.
3. 반환값으로 객체를 사용할수 있어야 한다.
4. 변수나 데이터 구조 안에 저장할 수 있어야 한다.
5. 할당에 사용된 이름에 관계없이 고유한 구별이 가능해야 한다.
1. 변수나 상수에 함수를 대입할 수 있음.
결과값을 넣는게 아니라, 함수를 넣는 것임. == 함수를 넣은 변수나 상수가 인자값도 받고, 반환도 가능하다는 것.
상수에 함수의 결과값을 넣으면 함수가 실행되고, 함수만 넣으면 함수가 실행이 안됨.
변수에 함수를 대입하면 그 함수는 함수타입(Function Type)이 됨.
함수타입 양식
(인자타입1, 인자타입2, ... ) -> 반환 타입
p370..
책에선 할당문을 쓸 때, 할당하려는 함수를 지정하는 것이 명확하지 않아서 타입어노테이션과 인자레이블의 유무로 명확하게 할당하려는 함수를 지정하게끔 설명이 되어 있으나 swift버전이 올라가면서 더 이상 불가능해 보인다.
그러나 튜플을 반환값으로 가지는 함수는 또 가능함..
보아하니 함수의 정의에서 지정한 매개변수 타입이 반환값 타입과 불일치 하는 문제같음
아래 말은 틀린 말임..
보이드의 첫 글자는 대문자여야 함.
여기까지 텀을 두고 다시 봤음
2. 함수의 반환 타입으로 함수를 사용할 수 있음
일급 객체로 대우받는 함수는 실행 결과로
정수, 실수, 문자열 등의 기본 자료형, 클래스, 구조체, 함수
반환 가능
함수정의에서 반환타입이 함수타입일 경우에 읽는 법은 왼쪽 화살표를 기준으로 왼쪽은 인자타입, 오른쪽은 반환타입으로 봄.
함수에서 함수를 호출하여 연산하는 방식을 이해하면 상수 p가 함수 desc와 같다는 것을 알 수 있음 그리고 아래도 마찬가지임.
이후 중첩함수에 대해서 다시 한번 나온다고 함.
3. 함수의 인자값으로 함수를 사용할 수 있음
콜백함수처럼 함수를 인자값으로 사용할 수 있다.
콜백함수 간단한 설명 ▼
함수 호출시, 함수값을 인자값으로 전달할 때, 호출되는 함수는 매개변수의 데이터 타입을 함수 타입으로 정의해야 함.
1 / 0 은 연산이 불가하다. ▼
callback 함수의 예시, 이런식으로 함수의 내부코드를 만지지 않고, 외부에서 함수의 실행 과정에 간섭할 수 있음.
defer블록의 특성
1. defer 블록은 작성된 위치와 순서에 상관없이 함수가 종료되기 직전에 실행된다.
2. defer 블록을 읽기 전에 함수의 실행이 종료될 경우 defer 블록은 실행되지 않는다.
3. 하나의 함수나 메소드 내에서 defer 블록을 여러 번 사용할 수 있다. 이때에는 가장 마지막에 작성된 defer 블록부터 역순으로 실행됨.
4. defer 블록을 중첩해서 사용할수 있다. 이때에는 바깥쪽 defer 블록부터 실행되며 가장 안쪽에 있는 defer 블록은 가장 마지막에 실행됨
5. 함수연산에 영향을 끼치지 않으면서 실행해야 할 다른 내용이 있을 때, 쓰거나 함수를 종료하기 직전에 정리해야 하는 변수나 상수값들을 처리하는 용도로 사용됨.
콜백함수의 가장 큰 목적은 함수 내부 코드를 건드리지 않고도 외부에서 실행흐름을 추가하기 위함
일회용 함수 == 익명함수 == 클로저(Closure)
'클로저는 뒤에서 다룸, 여기선 잘 모르겠음 '
함수의 중첩
함수 내에 다른 함수를 작성해서 사용할 수 있는데, 이를 중첩 함수(Nested Function)라고 함.
중첩함수는 외부함수(Outer Function)와 내부함수(Inner Function)로 구성됨.
외부함수 내에 작성할 수 있는 내부함수의 수는 제한이 없음 .
외부함수 안에 내부함수 안에 내부함수를 작성하는 것도 제한이 없음.
생명주기(Life Cycle)
외부함수는 프로그램이 실행될 때 생성되고, 프로그램이 종료될때 소멸함.
내부함수는 외부함수가 실행될때 생성되고, 외부함수가 종료될때 소멸함.
내부함수는 외부함수가 없으면 접근할 수 없기 때문에(ex 인자값을 외부에서 내부함수에 직접 곧바로 전달할 수 없음
외부의 코드로부터 차단되는데 이를 함수의 은닉성 이라고 함.
그래서 중첩함수는 함수의 은닉성을 높일 수 있음
예제의미 (일급함수의 특성이 중첩함수의 은닉성을 피해가게 하는 능력을 줌)
내부함수 inner를 외부함수의 실행결과(retrun inner)로 반환함 (== outer의 실행결과가 inner함수 그 자체가 됨. )
으로써 내부함수를 외부에서도 접근할수 있는 길이 열렸다는 것. 중첩함수의 정의대로라면 내부함수는 외부함수를 통해서만 접근할수 있는데(은닉성), 상수 fn1으로 언제든지. 내부함수에 접근이 가능하게 됨.
생명주기를 보면 inner는 외부함수 outer가 실행이 종료되면 소멸되어야 하지만, inner함수는 소멸하지 않고, fn1에 할당된 채로 남아서 fn1(30)으로 실행되는 것을 볼 수 있음. 외부함수에서 내부함수를 반환하면, 외부함수가 종료되더라도 내부함수의 생명이 유지되는 것을 볼 수 있음.
실제로는 12.라인 구문이 끝나면 외부함수는 제거되지만, 내부함수 inner는 결과값으로 반환되어 fn1에 참조되었으므로, '참조 카운터'가 존재함. 그래서 inner가 살아남을 수 있었던 것.
일급함수와 중첩함수의 성질을 더 이해하기 위한 예시 ▽
12. 라인이 실행이 종료되면서 basic함수에서 정의된 value 상수가 존재하지 않으므로 13. 라인에서 append함수가 들어간 result상수에서 오류가 나야 하지만 나지 않고 값을 정상적으로 반환함. 그 이유는 append 함수가 클로저(Closure)를 갖기 때문임.
클로저 (함수형 언어에서 공통적인 개념의 클로저임)
1. 클로저는 두 가지로 이루어진 객체. 1) 내부함수 2) 내부함수가 만들어진 주변환경
2. 외부함수 내에서 내부함수를 반환하고, 내부함수가 외부함수의 지역변수나 상수를 참조할 때 만들어짐.
-> 클로저란 내부함수와 내부함수에 영향을 미치는 주변환경(문맥 : context)를 모두 포함한 객체이다.
주변환경(문맥 : context)을 조금 더 정확하게 설명하면 문맥의 영역이 가지고 있는 변수나 상수와 같은 객체가 아니라 그 객체들이 가지고 있는 값
외부함수에서 정의된 객체가 내부함수에 의해 참조되고, 이 내부함수가 반환되어 참조가 유지되고 있는 상태라면 클로저에 의해 내부함수의 지역변수나 상수도 함께 저장이 된다고 함. 이를 값이 캡처(Capture)되었다. 고 표현함. 값의 캡처는 문맥에 포함된 변수나 상수의 타입이 기본 자료형이나 구조체 자료형일 때 발생하는데, 캡처기능은 클로저 고유 기능 중 하나임. (함수형 언어에서는 공통적으로 사용하는 개념)
클로저
(스위프트에서 지칭하는 클로저 내용정리 ▽)
스위프트에서 클로저로 일회용 함수를 작성할 수 있음.
일회용 함수 == 한 번만 사용할 구문들의 집합 && 함수로 작성해야 하는 제약조건이 있을 때 작성하는 함수
일회용 함수는 일회성 사용이기 때문에 함수의 이름을 작성할 필요가 없어서 익명(Anonymouse)함수로도 불림.
언어별 일회용 함수이름 참고 ▼
람다 참고 ▼
최종 정리해서
클로저는 자신이 정의되었던 문맥으로부터, 모든 상수와 변수의 값을 캡처하거나 레퍼런스를 저장하는 익명함수라고 할 수 있음
스위프트에서 클로저라고 부르는 객체는 다음 세가지 중 하나에 해당함.
1. 전역함수 : 이름이 있으며, 주변 환경에서 캡처할 어떤 값도 없는 클로저
2. 중첩함수 : 이름이 있으며 자신을 둘러싼 함수로부터 값을 챕처할 수 있는 클로저
3. 클로저 표현식 : 이름이 없으며 주변 환경으로부터 값을 캡처할 수 있는 경량 문법으로 작성된 클로저
클로저 표현식
함수 작성시 func 키워드와 함수명을 제외한 나머지 부분만 작성하는 경량문법을 씀
일반함수에선 반환타입을 쓰고 실행 블록 '{' 이 나오지만 클로저 표현식에선 in 으로 대신 함.
{ (매개변수) -> 반환 타입 in
실행할 구문
}
반환값이 없는 경우 cf) 반환타입이 있지만 생략된 경우와 구분하기 위해
Void 나 ( ) 로 반환값을 표시해줌.
{ ( ) -> Void in
print("클로저가 실행됩니다.")
}
or
{ ( ) -> ( ) in
print("클로저가 실행됩니다.")
}
클로저 표현식은 그 자체로 함수이며, 대부분 인자값으로 함수를 넘길 때 씀.
클로저 표현식 사용법 1
클로저 표현식 사용법 2
클로저 표현식과 경량 문법
클로저 표현식은 간결성을 극대화 하는 구문들로 이루어져 있어서 추가적인 경량문법이 존재함.
반환값을 생략하면 컴파일러가 구문 내의 반환값을 찾아 해당 타입으로 정의함. (타입추론 작동)
추가설명. ▽
트레일링 클로저(Trailing Closure)
클로저를 다른 함수의 인자값으로 전달할 때에는 자칫 가독성을 해치는 복잡한 구문이 만들어질 수 있음.
스위프트 코드 내에서 클로저를 인자값으로 주고 받을 때, 전달 시 문법을 변형할 수 있도록 지원함. == 트레일링 클로저 문법
함수의 마지막 인자값이 클로저일 때, 인자값 형식이 아나라 함수 뒤에 꼬리를 붙이는 식 (이때 인자레이블 생략)
( ) { ... }
함수 호출 연산자가 감싸는 범위가 줄어듦.(블록문 그레이스 { } 앞으로 나와)
이 부분은 실제 코드를 실행시 책과는 문법 동작의 결과값이 달라서 추후 확인하여 수정하기로 함.
▽
@escaping과 @autoescape
클로저를 함수나 메소드의 인자값으로 활용할 때에는 용도에 따라 @escaping나 @autoescape를 속성으로 부여가 가능함.
@escaping
속성은 인자값으로 전달된 클로저를 저장해 두었다가, 나중에 다른 곳에서도 실행될 수 있도록 허용해주는 속성임.
탈출 == 함수 내부 범위를 벗어나 실행되는 것을 의미
스위프트의 함수의 인자값으로 전달된 크롤저는 기본적으로 탈출불가(non - escape) 의 성격을 가짐.
-> 해당 클로저를 1. 함수 내에서 2. 직접 실행을 위해서만 사용해야 함을 의미(변수나 상수에 대입하면 내부함수를 이용한 캡처 기능을 이용해 클로저가함수 바깥으로 탈출이 가능하기 때문.
또한
인자값으로 전달된 클로저는 중첩된 내부 함수에서 사용할 수도 없음. 왜냐하면 컨텍스트 캡처를 통해서 탈출될 수 있기 때문
'ios > 문법' 카테고리의 다른 글
Swift 구조체와 클래스: 객체지향 스위프트 (0) | 2023.03.09 |
---|---|
옵셔널 Optional (0) | 2023.02.22 |
swift 집단 자료형 (0) | 2023.02.17 |
swift 기본문법 (0) | 2023.02.16 |