야곰님의 스위프트 프로그래밍 책으로 공부한 내용을 잊어버리지 않게 간단하게 정리한 글입니다.
관련 포스트
[Swift] 스위프트 프로그래밍 - Part1 - 1 : 스위프트? / 스위프트 장점 / 특징 / 명명 규칙 / 콘솔 로그 / 주석
[Swift] 스위프트 프로그래밍 - Part1 - 2 : 변수 / 상수 / 데이터 타입 기본 (Int, Bool, Float, Character, String, Any, AnyObject, nil)
[Swift] 스위프트 프로그래밍 - Part1 - 3 - 1 : 데이터 타입 고급 (Tuple, Array, Dictionary, Set)
[Swift] 스위프트 프로그래밍 - Part1 - 3 - 2 : 데이터 타입 고급(열거형 enum)
[Swift] 스위프트 프로그래밍 - Part1 - 5 : 연산자
[Swift] 스위프트 프로그래밍 - Part1 - 5 : 연산자
책 범위 : Part 1. 스위프트 기초 - 5. 연산자
연산자의 분류
분류 | 설명 | 예 |
단항 연산자 | 피연산자(연산 대상)가 한 개인 연산자 | !A |
이항 연산자 | 피연산자가 두개 | A + B |
삼항 연산자 | 피연산자가 세개 | A ? B : C |
전위 연산자 | 연산자가 피연산자 앞에 위치하는 연산자 | !A |
중위 연산자 | 연산자가 피연산자 사이에 | A + B |
후위 연산자 | 연산자가 피연산자 뒤에 | A! |
연산자의 종류
1. 할당(대입) 엽산자
값을 할당할 때 사용
연산자 | 부호 | 설명 |
할당(대입) 연산자 | A = B | A에 B의 값을 할당. 서로 다른 데이터 타입일 경우 오류 |
2. 산술 연산자
연산자 | 부호 | 설명 |
더하기 연산자 | A + B | A와 B를 더한 값을 반환 |
빼기 연산자 | A - B | A에서 B를 뺀 값을 반환 |
곱하기 연산자 | A * B | A와 B를 곱한 값을 반환 |
나누기 연산자 | A / B | A를 B로 나눈 값을 반환 |
나머지 연산자 | A % B | A를 B로 나눈 나머지를 반환 |
* 스위프트에서는 부동소수점 타입도 나머지 연산을 할 수 있다.
* 나누기 연산은 기존 프로그래밍 언어와 마찬가지로 소수점을 제외한 정수만을 결괏값으로 반환한다.
3. 비교 연산자
연산자 | 부호 | 설명 |
값이 같음 | A == B | A와 B가 값은 값인지 비교해 불리언 값을 반환 |
값이 크거나 같음 | A >= B | |
값이 작거나 같음 | A <= B | |
값이 큼 | A > B | |
값이 작음 | A < B | |
값이 같지 않음 | A != B | |
참조가 같음 | A === B | A와 B가 참조(레퍼런스) 타입일 때, A와 B가 같은 인스턴스를 가리키는지 비교해 불리언 값 반환 |
참조가 같지 않음 | A !== B | A와 B가 참조(레퍼런스) 타입일 때, A와 B가 같지 않은 인스턴스를 가리키는지 비교해 불리언 값 반환 |
패턴 매치 | A ~= B | A와 B의 패턴이 매치되는지 확인해 불리언 값 반환 |
* 스위프트의 유일한 참조 타입인 클래스의 인스턴스에서만 참조 비교 연산자를 사용할 수 있다.
스위프트의 기본 데이터 타입은 모두 구조체로 구현되어 있기 때문에 값 타입이다.
따라서 값의 비교 연산에는 ==을 사용하고 클래스의 인스턴스인 경우에만 ===을 사용한다.
(물론 다른 데이터 타입에서 === 등의 사용자 정의 연산자를 만든다면 다른 용도로 사용도 가능)
4. 삼항 조건 연산자
피연산자가 세 개인 연산자
연산자 | 부호 | 설명 |
삼항 조건 연산자 | Question ? A : B | Question(불리언 값)이 참이면 A를, 거짓이면 B 반환 |
5. 범위 연산자
값의 범위를 나타낼 때 사용
연산자 | 부호 | 설명 |
폐쇄 범위 연산자 | A...B | A부터 B까지의 수를 묶어 범위를 표현. A와 B를 포함 |
반폐쇄 범위 연산자 | A..<B | A부터 B 미만까지의 수를 묶어 범위를 표현. A포함 B미포함 |
단방향 범위 연산자 | A... | A 이상의 수를 묶어 범위를 표현. A포함 |
...A | A 이하의 수를 묶어 범위를 표현. A포함 | |
..<A | A 미만의 수를 묶어 범위를 표현. A미포함 |
6. 부울 연산자
연산자 | 부호 | 설명 |
NOT(부정) 부울 연산자 | !A | A(불리언 값)의 참, 거짓을 반전 |
AND 부울 연산자 | A && B | A와 B의 불리언 AND 논리 연산 실행 |
OR 부울 연산자 | A || B | A와 B의 불리언 OR 논리 연산 실행 |
7. 비트 연산자
연산자 | 부호 | 설명 |
NOT(부정) 비트 연산자 | ~A | A의 비트를 반전한 결과 반환 |
AND 비트 연산자 | A & B | A와 B의 비트 AND 논리 연산 실행 |
OR 비트 연산자 | A | B | A와 B의 비트 OR 논리 연산 실행 |
XOR 비트 연산자 | A ^ B | A와 B의 비트 XOR 논리 연산 실행 |
비트 이동 연산자(시프트 연산자) | A >> B, A << B | A의 비트를 B만큼 비트를 시프트(이동) |
8. 복합 할당 연산자
할당 연산자와 다른 연산자가 하는 일을 한 번에 할 수 있도록 연산자를 결합한 연산자
표현 | 설명 | 같은 표현 |
A += B | A와 B의 합을 A에 할당 | A = A + B |
-=, *=, /=, %=, <<=, >>=, &=, |=, ^= 다 같은 원리임 |
9. 오버플로 연산자
기존 프로그래밍 언어에서는 오버플로에 대한 추가 알고리즘 및 로직을 설계하는 것이 일반적이었다.
스위프트에서는 기본 연산자를 통해 오버플로에 대비할 수 있도록 준비해두었다.
연산자 | 부호 | 설명 |
오버플로 더하기 연산 | &+ | 오버플로에 대비한 덧셈 연산을 함 |
오버플로 빼기 연산 | &- | 오버플로에 대비한 뺄셈 연산을 함 |
오버플로 곱하기 연산 | &* | 오버플로에 대비한 곱셈 연산을 함 |
ex) UInt8 타입은 8비트 정수 타입으로 부호가 없는 양의 정수만을 표현하기 때문에 0 아래로 내려가는 계산을 하면 런타임 오류가 발생한다.
그렇지만 오버플로 빼기 연산을 사용하면 오류 없이 오버플로 처리를 해준다.
하지만 오버플로에 대한 이해 없이 사용한다면 엉뚱한 값을 구할 수 있다.
(범위를 넘어가는 경우 - 양의 무한대를 늘리면 음수로 다시 돌아가고, 음의 무한대를 줄이면 다시 양수로 래핑 된다.)
var unsignedInteger: UInt8 = 0
let errorUnderFlowResult: UInt8 = unsignedInteger -1 // Runtime Error
let underflowedValue: UInt8 = unsignedInteger &- 1 // 255
unsignedInteger = UInt8.max // 255
let errorOverflowResult: UInt8 = unsignedInteger + 1 // Runtime Error
let overflowedValue: UInt8 = unsignedInteger &+ 1 // 0
10. 기타 연산자
앞에서 설명한 연산자 외에 스위프트 라이브러리에 기본적으로 정의된 연산자
연산자 | 부호 | 설명 |
nil 병합 연산자 | A ?? B | A가 nil이 아니면 A를 반환하고, A가 nil이면 B를 반환함 |
부호 변경 연산자 | -A | A(수)의 부호를 변경 |
옵셔널 강제 추출 연산자 | O! | O(옵셔널 개체)의 값을 강제로 추출 |
옵셔널 연산자 | V? | V(옵셔널 값)를 안전하게 추출하거나, V(데이터 타입)가 옵셔널임을 표현 |
* nil 병합 연산자를 이용해 훨씬 안전하게 옵셔널을 다룰 수 있다. (옵셔널 강제 추출 연산자 사용은 지양하는 편이 좋음)
let valueInt: Int = someOptionalInt != nil ? someOptionalInt! : 0
let valueInt: Int = someOptionalInt ?? 0
연산자 우선순위와 결합방향
스위프트에서는 연산자 우선순위(Precedence)를 지정해 놓았다.
우선순위가 높은 연산자는 자신에 비해 우선순위가 낮은 연산자보다 먼저 실행된다.
또한 연산자가 연산하는 결합방향(Associativity)도 지정되어 있다.
결합방향은 같은 우선순위에 있는 연산자끼리 나열되었을 때 어느 방향부터 그룹 지을 것인지를 나타낸다.
ex) 1 + 2 + 3 + 4 -> 연산자 + 모두 같은 우선순위 -> +의 결합방향 왼쪽 -> (((1 +2) + 3) +4)
연산자들의 우선도와 결합방향을 알아보려면 스위프트 표준 라이브러리의 연산자 정의를 참고하면 된다.
* 연산자 우선순위 그룹 (precedencegroup)
higherThan, lowerThan, associativity 등으로 우선순위 및 결합 방향등을 지정해 놓은 것이다.
상대적인 수치이다.
precedencegroup AdditionPrecedence { // 더하기 연산자 우선순위 그룹
associativity: left
higherThan: RangeFormationPrecedence
}
사용자 정의 연산자
스위프트에서는 사용자가 원하는 대로 연산자 역할을 부여할 수 있다.
기존에 존재하지 않던 연산자 기호를 만들어 추가할 수도 있다.
* 할당 연산자(=)와 삼항 연산자(?:)는 사용자 정의 역할을 부여할 수 없다.
사용자 정의 연산자 구현
먼저 기존 연산자가 전위, 중위, 후위 중 어떤 연산자인지를 알아야 한다.
prefix |
전위 연산자는 연산자가 피연산자 앞에 위치하는 연산자를 의미 ex) NOT(부정) 부울 논리 연산자 ! |
infix |
중위 연산자는 피연산자 사이에 위치하는 연산자를 의미 ex) A + B |
postfix |
후위 연산자는 피연산자 뒤에 위치하는 연산자를 의미 ex) 옵셔널 강제 추출 연산자 - 0! |
operator | 연산자 의미 |
associativity | 연산자 결합 방향 |
precedence |
우선순위 의미 |
* 사용자 정의 연산자에 대해 더 자세히 알고 싶다면?
사용자 정의 연산자는 아스키 문자 /, =, -, +,!, *, %, <, >, &, |, ^,?, ~를 결합해서 사용한다.
마침표(.)는 사용할 수 있지만 맨 처음의 문자가 마침표 일 때만 연산자로 인식된다.
ex).+. / +.+의 경우 +연산자와.+ 연산자를 사용한 것으로 인식
물음표(?)와 느낌표(!)의 경우 사용할 수 있지만, 자체만으로는 사용자 정의 연산자를 정의할 수 없다.
(또한 전위 연산자는?,!로 시작하는 사용자 정의 연산자를 아예 정의할 수 없다.)
토큰으로 사용되는 =, ->, //, /*, */,.
전위 연산자 <, &,?
중위 연산자?
후위 연산자 >,!,? 등은 이미 스위프트에서 예약한 상태이기 때문에 재정의 할 수 없고, 사용자 정의 연산자로 사용될 수도 없다.
1. 전위 연산자 정의와 구현
- Int 타입의 제곱을 구하는 연산자로 **를 전위 연산자로 사용하는 예시
- 구현하는 방법
- 연산자 정의
- 어떤 데이터 타입에 이 연산자가 동작할 것인지 함수 구현
prefix operator ** // 전위 연산자 정의
// 전위 연산자 구현과 사용
prefix func ** (value: Int) -> Int {
return value * value
}
let minusFive: Int = -5
let sqrtMinusFive = **minusFive
print(sqrtMinusFive) // 25
* 이미 만들어 놓은 사용자 정의 전위 연산자를 다른 타입에서도 동작할 수 있도록 중복 정의도 가능하다.
* 스위프트 표준 라이브러리에 존재하는 전위 연산자에 기능을 추가할 때는 따로 연산자를 정의하지 않고 함수만 중복 정의하면 된다.
// 사용자 정의 전위 연산자 함수 중복 정의와 사용
prefix func ** (value: String) -> String {
return value + " " + value
}
let resultString: String = **"minha"
print(resultString)
prefix func ! (value: String) -> Bool {
return value.isEmpty
}
// 전위 연산자 함수 중복 정의와 사용
var stringValue: String = "minha"
var isEmptyString: Bool = !stringValue
print(isEmptyString)
stringValue = ""
isEmptyString = !stringValue
print(isEmptyString)
2. 후위 연산자 정의와 구현
- 사용자 정의 전위 연산자를 구현한 것과 크게 다르지 않다.
- postfix 키워드 사용
* 하나의 피연산자에 전위 연산과 후위 연산을 한 줄에 사용하게 되면 후위 연산을 먼저 수행한다.
3. 중위 연산자 정의와 구현
- 중위 연산자 정의도 전위, 후위 연산자 정의와 크게 다르지 않다.
- infix 키워드 사용
* 다만 우선순위 그룹을 명시해줄 수 있다.
우선순위 그룹을 명시하지 않는다면 우선순위가 가장 높은 DefaultPrecedence 그룹을 우선순위 그룹으로 갖게 된다.
이렇듯 사용자 정의 연산자는 클래스, 구조체 등에서 새로 정의하고, 중복 정의하며 유용하게 사용할 수 있다.
참고
아래를 참고해 정리한 내용입니다.
스위프트 프로그래밍 3판(야곰) - 한빛미디어
'iOS' 카테고리의 다른 글
[Swift] 스위프트 프로그래밍 - Part2 - 9 : 구조체와 클래스 (0) | 2021.04.21 |
---|---|
[Swift] 스위프트 프로그래밍 - Part1 - 6 : 흐름 제어 (446) | 2021.04.07 |
[Swift] 스위프트 프로그래밍 - Part1 - 3 - 2 : 데이터 타입 고급(열거형 enum) (0) | 2021.01.19 |
[Swift] 스위프트 프로그래밍 - Part1 - 3 - 1 : 데이터 타입 고급 (Tuple, Array, Dictionary, Set) (0) | 2020.12.21 |
[iOS - MongoDB Realm] 4-1. iOS SDK - Install Realm for iOS (0) | 2020.12.15 |
댓글