swift에서는 연산자가 어디에 위치하느냐도 중요하지만, 연산자 앞과 뒤 중 어디에 공백이 있는지도 중요하다. 예를 들어, A != B와 A! = B는 전혀 다른 의미이다.
연산자에 대한 개념은 다른 언어를 공부할 때 이미 대략적으로 습득하였기 때문에 다른 언어에서 흔히 쓰이지 않는 연산자와 알아두면 좋은 연산자에 대해서만 살펴보겠다.
말 그대로 값을 할당할 때 사용하는 연산자이다. 이미 다른 언어에서 할당(대입) 연산자를 많이 경험해보았겠지만 swift는 엄격한 문법이기 때문에 서로 다른 데이터 타입이라면 오류를 내뱉는다는 사실을 상기시키자.
연산자 | 부호 | 설명 |
---|---|---|
할당(대입) 연산자 | 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-1의 범위 |
단방향 범위 연산자 | A... | A~의 범위 |
...A | ~A의 범위 | |
..<A | ~A-1의 범위 |
var i: Int = 0
for i in 1...5 {
print(i)
}
결과
1
2
3
4
5
var i: Int = 0
for i in 1..<5 {
print(i)
}
결과
1
2
3
4
기존 프로그래밍 언어와는 다르게 swift는 기본 연산자를 통해 오버플로우에 대비할 수 있도록 설계되었다. 이 연산자를 사용하면 자동으로 오버플로우에 대한 처리를 할 수 있다.
연산자 | 부호 | 설명 |
---|---|---|
오버플로우 더하기 연산 | &+ | 오버플로우에 대비한 덧셈 연산 |
오버플로우 빼기 연산 | &- | 오버플로우에 대비한 뺄셈 연산 |
오버플로우 곱하기 연산 | &* | 오버플로우에 대비한 곱셈 연산 |
var unsignedInteger: UInt = 0
let errorUnderflowResult: UInt = unsignedInteger - 1
결과
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
오버플로우 연산자를 사용하면 해결할 수 있다.
var unsignedInteger: UInt = 0
let underflowedValue: UInt = unsignedInteger &- 1
연산자 | 부호 | 설명 |
---|---|---|
nil 병합 연산자 | A??B | A가 nil이 아니면 A를 반환하고, A가 nil이면 B를 반환 |
부호변경 연산자 | -A | A의 부호를 변경 |
옵셔널 강제 추출 연산자 | O! | O의 값을 강제로 추출 |
옵셔널 연산자 | V? | 옵셔널 값을 안전하게 추출하거나, 옵셔널임을 표현 |
프로그래머가 원하는대로 연산자를 정의할 수 있는데 할당 연산자(=)와 삼항 연산자(?:)는 정의할 수 없다는 예외가 있다.
전위 연산자는 prefix, 후위 연산자는 postfix, 중위 연산자는 infix 키워드를 사용한다.
기존에 없던 전위 연산자를 만들고 싶다면 아래와 같이 연산자 정의를 먼저 해줘야 한다.
prefix operator **
어떤 Int 타입의 제곱을 구하는 연산자를 만들기 위해 아래와 같이 구현하면 된다.
prefix func ** (value: Int) -> Int {
return value * value
}
전위 연산자와 마찬가지로 연산자 정의를 먼저 해줘야 한다.
postfix operator ***
어떤 Int 타입의 값에 10을 더해주는 연산자를 만들기 위해 아래와 같이 구현하면 된다.
postfix func *** (value: Int) -> Int {
return value + 10
}
전위 연산자나 후위 연산자와 크게 다르지 않지만 중위 연산자는 우선순위 그룹을 명시해줄 수 있다.
precedencegroup 우선순위 그룹 이름 {
higherThan: 더 낮은 우선순위 그룹 이름
lowerThan: 더 높은 우선순위 그룹 이름
associativity: 결합방향(left / right / none)
assignment: 할당방향 사용(true / false)
}
앞서 설명한 두 연산자와 마찬가지로 연산자 정의를 먼저 해줘야 한다.
infix operator ****
뒤에 오는 문자열이 앞에 있는 문자열에 속해있는지 알려주는 연산자를 만들기 위해 아래와 같이 구현하면 된다.
func **** (lhs: String, rhs: String) -> Bool {
return lhs.contains(rhs)
}