본문 바로가기
iOS

[Swift] 스위프트 프로그래밍 - Part1 - 5 : 연산자

by 건복치 2021. 2. 16.
반응형
야곰님의 스위프트 프로그래밍 책으로 공부한 내용을 잊어버리지 않게 간단하게 정리한 글입니다.

관련 포스트

[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 타입의 제곱을 구하는 연산자로 **를 전위 연산자로 사용하는 예시

 

- 구현하는 방법 

  1. 연산자 정의
  2. 어떤 데이터 타입에 이 연산자가 동작할 것인지 함수 구현 
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판(야곰) - 한빛미디어
반응형

댓글