기본 연산자는 코딩을 하면서 거의 기본 중에 기본이라고 볼 수 있다. 과연 Swift는 다른 언어와 어떠한 점이 같고, 어떠한 점이 다를까?
Swift에서 기본 연산자란 대입, 연산, 비교를 수행한다. 값을 변경, 확인, 결합하기 위해서 사용한다. 예를 들면 +
는 두 숫자를 더하게 되고 AND 연산자 (&&
)는 두 Boolean값을 결합하게 된다.
용어 (Terminology)
연산자는 단항, 이항, 삼항으로 나눌 수 있다.
- 단항의 경우
-a
처럼 단일 항목에 적용된다.!b
,c!
처럼 말이다. - 이항의 경우
2 + 3
처럼 2개의 항목에 동작하고 2개의 항목 사이에 위치한다. - 삼항의 경우 Swift는 하나의 삼항 연산자인 조건 연산자만 있고
a ? b : c
형태로 이루어진다.
연산자 (operators) 는 피연산자 (operands) 값에 영향을 준다고 볼 수 있다.
대입 연산자 (Assignment Operator)
대입연산자 a = b
에서 a
는 b
의 값으로 초기화 되거나 업데이트 된다.
let b = 10
var a = 5
a = b
// a is now equal to 10
let (x, y) = (1, 2)
// x is equal to 1, and y is equal to 2
Swift에서는 C와 Objective-C에서의 대입연산자와 다르게 값을 반환하지 않는다. 따라서 아래 예문에서 =
를 ==
로 바꿔줘야 한다.
if x = y {
// This is not valid, because x = y does not return a value.
}
산술 연산자 (Arithmetic Operators)
Swift에서는 모든 숫자 타입에 대해서 4가지의 기본 연산자인 덧셈 +
뺄셈 -
곱셈 *
나눗셈 /
를 제공한다.
1 + 2 // equals 3
5 - 3 // equals 2
2 * 3 // equals 6
10.0 / 2.5 // equals 4.0
나머지 연산자 (Remainder Operator)
나머지 연산자 a % b
는 b
가 a
안에 몇 번 들어갈지를 계산하고 남은 값을 반환한다.
Note: 나머지 연산자는 다른 언어에서는 모듈로 연산자 (modulo operator)라고 한다.
나머지 연산자는 아래와 같이 동작한다 9 % 4
를 했을 때, 9 안에는 아래와 같이 4가 두 번 들어가고 1이 남는다.
9 % 4 // equals 1
a % b
의 결과를 구하기 위해 %
연산자는 a = (b * some multiplier) + remainder
를 계산하고 remainder
를 반환한다. 따라서 a
에 음수를 넣더라도 같은 방법으로 계산된다. -9 = (4 * -2) + -1
이므로 -1
의 나머지를 얻는다.
-9 % 4 // equals -1
단항 연산자 (Unary Operator)
솔직히 단항연산자를 설명하는 것보다는 아래의 예시를 보는 것이 편하다. 단항 빼기 연산자는 공백없이 값 바로 앞에 붙이게 된다.
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
복합 대입 연산자 (Compound Assignment Operators)
C처럼 Swift는 대입 =
과 다른 연산자를 결합한 복합 대입 연산자를 쓸 수 있다!
var a = 1
a += 2
// a is now equal to 3
위의 a += 2
는 a = a + 2
의 짧은 표현이다. 하지만 복합 대입 연산자는 값을 반환하지 않아 let b = a += 2
로 작성은 할 수 없다. 당연하다 a
의 값을 업데이트 하는 것이지 3이라는 값을 반환하지는 않는다.
비교 연산자 (Comparison Operators)
- 같음 (
a == b
), 다름 (a != b
) - 보다 큼 (
a > b
) 보다 작음 (a < b
) - 보다 크거나 같음 (
a >= b
) 보다 작거나 같음 (a <= b
)
각 비교 연산자는 아래와 같이 Bool 값을 반환한다.
1 == 1 // true because 1 is equal to 1
2 != 1 // true because 2 is not equal to 1
2 > 1 // true because 2 is greater than 1
1 < 2 // true because 1 is less than 2
1 >= 1 // true because 1 is greater than or equal to 1
2 <= 1 // false because 2 is not less than or equal to 1
Note : Swift는 2개의 객체 참조가 동일한지 판별하기 위해 (===
) 나 (!==
) 의 연산자도 있다. 이게 뭔가 싶을 것이다. 자세한 내용은 뒤에서 다룰 예정이다.
비교연산자는 아래와 같이 조건 구문에서 활용된다. name
이라는 값이 "world"
라면 "hello, world"
를 출력해주세요! 라는 의미이다. if
구문에 대한 자세한 흐름은 뒤에 Control Flow 파트에서 다룰 예정이다.
let name = "world"
if name == "world" {
print("hello, world")
} else {
print("I'm sorry \(name), but I don't recognize you")
}
// Prints "hello, world", because name is indeed equal to "world".
아래의 내용부터 약간 복잡해진다. 같은 타입과 같은 개수의 값을 가지고 있는 튜플도 비교가 가능하다! 튜플은 두 개의 값이 다를 때까지 왼쪽에서 오른쪽으로 하나씩 비교한다.
(1, "zebra") < (2, "apple") // true because 1 is less than 2; "zebra" and "apple" are not compared
(3, "apple") < (3, "bird") // true because 3 is equal to 3, and "apple" is less than "bird"
(4, "dog") == (4, "dog") // true because 4 is equal to 4, and "dog" is equal to "dog"
1보다 2가 크기 때문에 첫 번째 줄은 true
값을 반환한다. 두 번째 줄은 3으로 첫 번째 값이 같기 때문에 두 번째 값을 비교하게 된다. apple
은 bird
보다 작은 값이기 때문에 true
값을 반환한다.. 왜냐하면 a
가 b
보다 앞에 있기 때문이다. 세 번째 줄은 모든 값이 같기 때문에 true
이다.
("blue", -1) < ("purple", 1) // OK, evaluates to true
("blue", false) < ("purple", true) // Error because < can't compare Boolean values
하지만 위와 같이 Bool
값은 비교가 불가능하기 때문에 비교연산자로 비교가 불가능한 값이 포함된다면 비교가 불가능하다. 또한 Swift 는 기본적으로 7개 미만의 요소를 가지고 있는 튜플만 비교해 준다. 그 이상은 비교 연산자를 직접 구현해야 한다.
삼항 조건 연산자 (Ternary Conditional Operator)
삼항 조건 연산자의 question ? answer1 : answer2
형태의 3가지 부분으로 이루어져 있다. 나는 SwiftUI 를 사용하면서 이 삼항 조건 연산자를 아주 즐겨 쓴다. 삼항 조건 연산자는 아래의 코드를 줄여서 표현한 것과 같다.
if question {
answer1
} else {
answer2
}
즉 question
이 true
라면 첫 번째 값인 answer1
값을 반환하고, false
라면 answer2
값을 반환한다.
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight is equal to 90
위의 코드를 분석해 보면 hasHeader
가 true
이기 때문에 결국 rowHeight
는 40 + 50
인 셈이다. 만약 삼항 조건 연산자를 쓰지 않고 위의 코드를 표현해 본다면...
let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
rowHeight = contentHeight + 50
} else {
rowHeight = contentHeight + 20
}
// rowHeight is equal to 90
이렇게 될 것이다. 그러면 무조건 삼항 조건자로 코드를 간결하게 나타내는 게 좋은 것 아닌가? 라고 생각할 수도 있지만 삼항 조건 연산자를 너무 남용한다면 읽기 어려운 코드가 될 수 있다!
Nil-결합 연산자 (Nil-Coalescing Operator)
nil 결합 연산자 ( a ?? b
) 는 옵셔널인 a
에 값이 있다면 a
의 값을 풀거나 (unwrap) 값이 없다면 기본값인 b
를 반환한다. a
는 항상 옵셔널 값이여야만 하고 b
는 a
에 저장된 타입과 같아야 한다. 아래와 같은 코드를 간결하게 나타낸 것이 a ?? b
라고 할 수 있다.
a != nil ? a! : b
공식 문서와 다르게 약간 변형해 봤다.
let a = 1
var b: Int? // defaults to nil
var c = b ?? a
// b is nil, so c is set to the default of 1
a
를 1
으로 두고 b
가 nil
값일 경우 c
는 a
의 값인 1
값을 가지게 된다.
b = 2
c = b ?? a
// b is not nil, so c is set to 2
만약 b
가 nil
값이 아닌 2
라는 값이 있을 때, c
는 2
라는 값으로 설정된다.
범위 연산자 (Range Operators)
값의 범위를 표현할 때 범위연산자를 사용한다.
닫힌 범위 연산자 (Closed Range Operator)
닫힌 범위 연산자인 ( a...b
) 는 값 a 와 b 가 포함된 a 부터 b 까지의 범위 실행을 정의한다. a 의 값은 b 보다 클 수 없다.
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
반-열림 범위 연산자 (Half-Open Range Operator)
이 연산자 ( a..<b
) 는 b 가 포함되지 않은 a 부터 b 까지의 범위를 정의한다. 이와 같은 범위 연산자는 배열과 함께 사용하면 좋다.
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("Person \(i + 1) is called \(names[i])")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
단-방향 범위 (One-Sided Ranges)
아래와 같이 쓸 수 있다.
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names[2...] {
print(name)
}
// Brian
// Jack
for name in names[...2] {
print(name)
}
// Anna
// Alex
// Brian
for name in names[..<2] {
print(name)
}
// Anna
// Alex
위와 같은 상황 말고도 아래와 같이 사용 될 수 있다. range
자체를 5
이하인 수들로 정해줄 수 있다.
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
논리 연산자 (Logical Operators)
Swift에서는 3개의 논리 연산자가 있다.
- 논리적 NOT (
!a
) - 논리적 AND (
a && b
) - 논리적 OR (
a || b
)
논리적 NOT 연산자 (Logical NOT Operator)
논리적 NOT 연산자 ( !a
) 는 Boolean
값을 true
인 값을 false
로, false
인 값을 true
로 변환한다. 아래처럼 false
인 a
의 앞에 NOT 연산자를 붙여주면 true
로 변하는 것을 볼 수 있다.
let a = false
if !a {
print("a is true!")
}
// Prints "a is true!"
논리적 AND 연산자 (Logical AND Operator)
논리적 AND 연산자. ( a && b
) 는 두 값이 모두 true
여야 true
의 값이 반환된다. 두 값중 하나라도 false
라면 false
값이 반환된다. 첫번째 값이 false 라면 두번째 값은 살펴보지 않는다. 이 것을 연산 생략 (short-circuit evaluation) 이라 한다.
논리적 OR 연산자 (Logical OR Operator)
논리적 OR 연산자 ( a || b
) 는 두 값중 하나라도 true
이면 true
값을 반환시킨다.
논리적 연산자 결합 (Combining Logical Operators)
이제 위 두가지 논리적 연산자를 결합하여 표현식을 생성할 수 있다.
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
이런식으로 enteredDoorCode
는 true
여야 하고, 나머지 세 개중 하나라도 true
라면 true
의 값을 반환한다.
Note: Swift 의 논리적 연산자&&
와||
는 왼쪽 우선결합 (Left-associative) 이다. 여러 개의 논리적 연산자로 이루어진 복합 표현식은 가장 왼쪽부터 판단한다.
명시적 소괄호 (Explicit Parentheses)
복합 표현식을 읽기 쉽게 하기 위해 아래와 같은 소괄호를 포함할 수 있다. 가독성은 항상 간결성보다 선호되기 때문에 코드 작성자의 의도를 표현하기 위해서 소괄호를 사용해 주는 것이 좋다고 한다.
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
'Swift > Swift 공식 문서' 카테고리의 다른 글
[Swift] 함수 (Functions) (0) | 2023.05.21 |
---|---|
[Swift] 제어 흐름 (Control Flow) (1) | 2023.05.19 |
[Swift] 콜렉션 타입 (Collection Types) (1) | 2023.05.19 |
[Swift] 문자열과 문자 (Strings and Characters) (1) | 2023.05.18 |
[Swift] 구조체와 클래스 (Structures and Classes) (0) | 2023.04.30 |