Swift의 연산자는 특정 문자로 표현한 함수라고 생각할 수 있다.
따라서 특정 연산자의 역할을 바꿀 수도 있다.
기본적으로 연산자는 연산 되는 값의 수 또는 연산자의 위치에 따라 분류할 수 있다.
예를 들어 !A의 경우는 단항 연산자 이고, 전위 연산자 이다.
말 그대로 값을 할당하는 경우에 쓰는 연산자이다.
A = B // A에 B의 값을 할당 (같은 데이터 타입이어야 함)
산술 즉, 수학에서 쓰이는 연산자와 같다.
A + B // A 더하기 B
A - B // A 빼기 B
A * B // A 곱하기 B
A / B // A 나누기 B
A % B // A 나누기 B의 나머지
두 값을 비교하는 경우에 쓴다.
조건문에서 많이 쓰인다.
두 값을 비교하여 불리언 값(true/false)을 반환한다.
A == B // A와 B가 같은 값이면 true
A ~= B // A와 B가 같은 패턴이면 true
A >= B // A가 B보다 크거나 같은 값이면 true
A <= B // A가 B보다 작거나 같은 값이면 true
A > B // A가 B보다 큰 값이면 true
A < B // A가 B보다 작은 값이면 true
A != B // A와 B가 다른 값이면 true
A === B // A와 B가 레퍼런스 타입일 때 같은 인스턴스를 가리키면 true
A !== B // A와 B가 레퍼런스 타입일 때 다른 인스턴스를 가리키면 true
연산 대상이 세 개인 경우이다.
Question ? A : B // Question(bool값)이 true이면 A, false이면 B 반환
예제를 보면 더 이해가 쉽다.
아래의 예제는 a가 b보다 값이 더 큰지 비교(a > b)하여 값이 true이면 a false이면 b를 반환한다.
📄 입력
import UIKit
var a: Int = 2
var b: Int = 5
var whichIsBigger: String = a > b ? "a" : "b"
print(whichIsBigger)
💻 출력
b
값의 범위를 나타내는 경우 사용한다.
A...B // A 이상 B 이하 (A와 B 포함)
A.. < B // A 이상 B 미만 (A 포함, B 미포함)
A... // A 이상
...A // A 이하
.. < A // A 미만
불리언 값의 논리 연산을 하는 경우 사용한다.
!A // A가 아님 (true/false 반전)
A && B // A AND B
A || B // A OR B
값의 비트 논리 연산을 위해 사용한다.
~A // A의 비트 반전
A & B // A와 B의 비트 AND 논리 연산
A | B // A와 B의 비트 OR 논리 연산
A ^ B // A와 B의 비트 XOR 논리 연산
A >> B // A의 비트 B만큼 이동(시프트)
A << B // A의 비트 B만큼 이동(시프트)
연산자를 결합한 것을 말한다.
A += B // A = A + B
A -= B // A = A - B
A *= B // A = A * B
A /= B // A = A / B
A %= B // A = A % B
A &= B // A = A & B
A |= B // A = A | B
A ^= B // A = A ^ B
A <<= B // A = A << B
A >>= B // A = A >> B
오버플로 가능성이 있는 연산을 하는 경우 오버플로 연산자를 사용하여 오버플로 처리가 가능하다.
&+ // 오버플로에 대비한 더하기
&- // 오버플로에 대비한 빼기
&* // 오버플로에 대비한 곱하기
A ?? B // A가 nil 아니면 A, A가 nil이면 B 반환 -> Optional을 사용할 때 유용함
-A // A의 부호 변경
O! // Optional 개체의 값을 강제 추출
V? // Optional의 값을 안전하게 추출하거나 V가 Optional 타입임을 표현
Swift에서는 연산자 우선순위와 연산자가 연산하는 결합방향을 지정해두었다.
따라서 코딩하다가 헷갈리면 찾아보면 된다.
Swift 연산자의 우선순위는 절대치가 아닌 상대적 수치이다.
Swift 표준 라이브러리의 연산자 정의를 참고하자.
참고로 표준 라이브러리에 infix라는 키워드가 많이 나오는데, 이는 중위 연산자를 뜻한다.
Custom Operators란 사용자 정의 연산자이다.
사용자 즉, 프로그래머가 연산자의 정의를 자기가 부여할 수 있다.
사용법은 다음과 같다.
ASCII 문자
/, =, -, +, !, *, %, <, >, &, |, ^, ?, ~를 결합해서 사용한다.
마침표(.)는 사용할 수 있는데 맨 처음 문자가 마침표일 때만 연산자로 인식된다.
물음표(?)의 경우 사용자 정의 연산자에 포함시킬 수 있으나, 물음표 자체만으로는 할 수 없다.
(느낌표(!)도 마찬가지이다.)
할당 연산자(A = B)와 삼항 연산자(Question ? A : B)에는 사용자 정의 역할을 부여할 수 없다.
토큰으로 사용되는
=, ->, //, /*, */, .은 사용할 수 없다.
전위 연산자
<, &, ?, 중위 연산자?, 후위 연산자>, !, ?는 사용할 수 없다.
어떤 수의 제곱을 구하는 전위 연산자 **을 정의한다고 하면 다음과 같이 할 수 있다.
prefix operator **
그리고 아래와 같이 fun(함수 키워드)로 전위 연산자 **을 추가해준다.
📄 입력
import UIKit
prefix operator **
prefix func ** (value: Int) -> Int {
return value * value
}
print(**5)
💻 출력
25
만약에 이미 존재하는 전위 연산자에 기능을 추가하고 싶은 경우 함수 중복 정의를 사용하면 된다.
예를 들어 느낌표(!) 연산자를 문자열에도 사용하도록 하는 경우를 보자.
📄 입력
import UIKit
prefix func ! (value: String) -> Bool {
return value.isEmpty
}
var name = "Vina"
print(!name)
name = ""
print(!name)
💻 출력
false
true
이번에는 어떤 수의 세 제곱을 구하는 후위 연산자 ***을 정의한다고 하면 다음과 같이 할 수 있다.
postfix operator **
그리고 전위 연산자 정의하는 것과 마찬가지로 아래와 같이 fun(함수 키워드)로 전위 연산자 ***을 추가해준다.
📄 입력
import UIKit
postfix operator ***
postfix func *** (value: Int) -> Int {
return value * value * value
}
print(5***)
💻 출력
125
만약 전위 연산과 후위 연산을 한 줄에서 사용하게 되면, 후위 연산을 먼저 수행한다.
위에서 정의한 전위 연산 **과 후위 연산 ***을 사용하여 **2*** 이러한 연산을 하게 된다고 해보자.
그럼 우선 후위 연산인 2의 세 제곱(2 * 2 * 2)을 계산하여 8 이 나오고,
다음으로 전위 연산인 8의 제곱을 하여 64 가 나온다.
아래의 코드를 참고하자.
📄 입력
import UIKit
prefix operator **
postfix operator ***
prefix func ** (value: Int) -> Int {
return value * value
}
postfix func *** (value: Int) -> Int {
return value * value * value
}
print(**2***)
💻 출력
64
중위 연산자도 정의하는 것은 전위나 후위 연산자와 비슷하다.
다만 중위 연산자의 경우, 우선순위 그룹을 명시해줄 수 있는 점이 다르다.
📄 입력
import UIKit
import Foundation // contain(_:) 메서드 사용을 위해 Foundation 프레임워크를 import
infix operator **** : MultiplicationPrecedence // infix operater 연산자명 : 우선순위 그룹 명시
func **** (sentence: String, word: String) -> Bool {
return sentence.contains(word)
}
let introduce = "Hello my name is Vina"
let name = "Vina"
print(introduce****name)
💻 출력
true
연산자 우선순위 그룹을 정의하는 방법은 precedencegroup 뒤에 그룹명을 써주면 된다.
정의하는 방법은 아래와 같다.
precedencegroup 우선순위 그룹 이름 {
higherThan: 더 낮은 순위 그룹 이름
lowerThan: 더 높은 순위 그룹 이름
associativity: 결합방향 (left / right / none)
assignment: 할당방향 사용 (true / false)
}
associativity의 경우 결합방향을 명시할 수 있는데 명시를 안하는 경우 디폴트로 none이 설정된다.
만약 결합방향이 none 즉, 없는 상태이면 이 연산자는 여러번 연달아 사용할 수 없다.
중위 연산자를 정의할 때 우선순위 그룹을 명시하지 않는 경우,
우선순위가 가장 높은 DefaultPrecedence 그룹을 우선순위 그룹으로 갖게 된다.
매번 포스팅마다 마무리를 쓸 때가 가장 뿌듯하다.
오늘은 컨디션이 안좋다는 핑계로 연산자만 정리하려고 한다.
연산자는 사실 대충 정리하려고 했는데 암튼 (내 기준) 나름 열심히 했다.
이제 책 5장까지 정리했는데 이번주에 12장까지 정리하겠다는 야무진 꿈은,,
이번 주는 8-9장까지만 정리하는 것으로 방금 내 자신과 타협봤다,, ଘ(੭ˊ꒳ˋ)੭✧
아무튼 아쟈아자,,📚✨