반응형
Overview
- operator(연산자)는 값을 확인, 변경 또는 결합하는 데 사용되는 특수기호 또는 구문(phrase)이다.
- 예를 들어 덧셈 연산자 (+)는 두 수를 더해주며 논리 AND 연산자 (&&)은 두 개의 Boolean 값을 결합해준다.
- Swift는 C와 같은 다른 언어에서 사용되는 연산자를 지원한다.
- 코딩 과정에서 공통으로 발생될 수 있는 오류를 제거하여 연산자의 일부 능력을 향상시킨 형태로 제공한다.
- = 연산자는 == 연산자와 혼동하여 사용되지 않도록 값을 리턴하지 않는다.
- 산술 연산자 (+, -, *, /, %)는 type이 제공하는 값 범위를 벗어난 overflow를 감지하여 예측되지 않은 결과를 막기 위해 오류를 발생시킨다.
- Swift의 overflow 연산자를 활용하여 값 overflow 행위를 선택할 수 있다. [Overflow Operator 참조]
- Swift는 C에서 찾을 수 없는 범위 연산자를 제공한다.
- 범위 값에 함축된 표현으로 a..<b 나 a...b 의 형태를 사용한다.
- 이 단원에서는 공통적으로 사용되는 연산자를 다루지만 [Advanced Operators] 를 참조해보면...?
- Swift의 진보된 연산자 기능을 소개 한한다.
- custom 연산자를 정의하는 방법을 소개한다.
- custome type에 표준 연산자를 구현하는 방법을 소개한다.
Terminology
- 연산자는 unary(단항), binary(이항), ternary(삼항)으로 구분할 수 있다.
- unary(단항) 연산자는 하나의 target에서 운영되는 연산자이다. (예를 들어 -a)
- unary prefix 연산자는 target의 앞쪽에 등장한다. (예를 들어 !b)
- unary postfix 연산자는 target의 뒤쪽에 등장한다. (예를 들어 c!)
- Binary(이항) 연산자는 두 개의 target에서 운영되는 연산자이다. (예를 들어 2 + 3)
- 두개의 target 사이에서 사용되기 때문에 infix이다.
- Ternary(삼항) 연산자는 세 개의 target에서 운영되는 연산자이다.
- C 언어처럼 Swift는 오직 하나의 삼항 연산자를 갖고 있다.
- 삼항 조건 연산자 Ternary conditional operator (a ? b : c).
- 연산자가 영향을 줄 수 있는 값은 피연산자(operand)이다.
- 1 + 2 라는 표현이 있을 때,
- + 는 이항 연산자이며 두 개의 operand는 1 과 2이다.
Assignment Operator
- 할당 연산자 (a = b)는 a의 값을 b의 값으로 생성(initializes)하거나 갱신(updates) 시켜준다.
let b = 10
var a = 5
a = b
// a is now equal to 10
- 만약 할당 연산자의 우측면이 tuple이라면, 한 번에 여러 개의 상수나 변수로 분리해서 저장할 수 있다.
let (x, y) = (1, 2)
// x is equal to 1, and y is equal to 2
- C와 Objective-C에서의 할당 연산자와는 다르게 Swift에서의 할당 연산자는 값을 return 하지 않는다.
- 다음과 같은 코드는 동작하지 않는다.
if x = y {
// This isn't valid, because x = y doesn't return a value.
}
- 위 코드는 == 연산자를 사용할 것을 의도한 코드가 의문의 사유로? 할당 연산자로 사용되는 상황을 예방시켜준다.
Arithmetic Operators
- Swift는 모든 숫자 타입에 대하여 4가지의 표준 산술 연산자를 지원한다.
- Addition (+)
- Subtraction (-)
- Multiplication (*)
- Division (/)
1 + 2 // equals 3
5 - 3 // equals 2
2 * 3 // equals 6
10.0 / 2.5 // equals 4.0
- C와 Objective-C에서의 산술 연산자와는 다르게 Swift의 산술 연산자는 기본적으로 값이 overflow 되는 것을 허용하지 않는다.
- Swift의 overflow 연산자를 사용하면 overflow가 발생했을 때 어떤 행위를 취할 것인지 선택할 수 있다. (예를 들어 &+ b)
"Hello" + "World"
// equals "Hello World"
- 위와 같이 덧셈 연산자는 문자열 접합 (string concatenation) 기능을 지원한다.
Remainder Operator
- 나머지 연산자 (a % b)는 a의 내부에 맞추기 위해 b가 특정 횟수만큼 사용되었을 때 발생될 수 있는 나머지를 의미한다.
Note
나머지 연산자 (%)는 다른 언어에서 modulo 연산자로 알려져 있습니다. 하지만 음수일 때 Swift에서 나머지 연산의 동작은 엄밀하게 말하자면 modulo 연산이라기보다 remainder에 가깝습니다.
- 나머지 연산이 동작하는 방법을 소개한다.
- 9 % 4를 계산하기 위해 9 내부에 4가 몇 번 들어가는지 확인해야 한다.
- 9 내부에 2개의 4를 채워 넣으면 나머지(remainder) 1이 남는다. (orange 색으로 표현되었다)
- Swift에서 다음과 같은 방식으로 쓰인다.
9 % 4 // equals 1
- a % b 의 정답을 결정하기 위해서 % 연산자는 다음과 같은 방정식을 계산하여 출력 값으로 나머지(remainder)를 return 한다.
a = (b x some multiplier) + remainder
- 이때 some multiplier은 a에 b를 채워 넣을 수 있는 가장 큰 횟수 값이다.
- 9에 4를 채워 넣는다면 다음과 같은 방정식을 사용할 수 있다.
9 = (4 x 2) + 1
- a가 음수일 때 나머지를 계산한다고 해도 같은 방식이 적용된다.
-9 % 4 // equals -1
- -9와 4의 나머지 연산을 방정식에 대입해보면 다음과 같다.
-9 = (4 x -2) + -1
- 만약 b의 부호가 음수라면 b의 부호가 무시된다. 다시 말해 a % b와 a % -b의 계산 결과가 언제나 동일한 결과를 도출한다.
Unary Minus Operator
- 숫자 값의 부호는 - 기호를 앞에 붙임으로써 뒤집힐(toggle) 수 있으며 unary(단항) minus operator로 알려져 있다.
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
Unary Plus Operator
- unary plus operator (+)는 어떠한 변화 없이 단순히 값을 return 시켜준다.
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
- unary plus operator 가 아무런 작업을 취하지 않는다고 해도
- 음수에 unary minus operator를 사용할 때
- 코드에 양수에 대한 대칭성을 제공하는 데 사용할 수 있다.
Compound Assignment Operators
- C와 같이, Swift는 할당 연산자 = 와 다른 연산자가 결합된 compound assignment 연산자를 제공한다.
- 다음의 코드는 addition assignment 연산자 (+=)의 예시이다.
var a = 1
a += 2
// a is now equal to 3
- a += 2 라는 표현식은 a = a + 2 를 줄여서 표기한 것이다.
- 덧셈과 할당 연산자가 하나의 연산자로 결합되어서 두 가지 작업을 동시에 수행한다.
Note
compound assignment 연산자는 값을 리턴하지 않습니다. 예를 들어 let b = a += 2의 형태로 코드를 작성할 수 없습니다.
- Swift standard library에서 제공하는 연산자에 대한 자세한 사항은 Operator Declarations 를 확인하세요.
Comparison Operators
- Swift는 다음과 같은 비교 연산자들을 지원한다.
- Equals to ( a == b )
- Not equal to ( a != b )
- Greater than ( a > b )
- Less than ( a < b )
- Greater than or equal to ( a >= b )
- Less than or equal to ( a <= b )
Note
Swift는 두 개의 identity 연산자 ( === and !== )를 제공합니다. 두개의 object 참조자(reference)가 동일한 object instance를 지칭하고 있는지 확인할 때에 사용합니다. 자세한 내용은 identity Operators 를 확인하세요.
- 각각의 비교 연산자는 표현식이 참값을 갖는지 아닌지를 지칭하는 Bool 값을 리턴한다.
1 == 1 // true because 1 is equal to 1
2 != 1 // true because 2 isn't 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 // fale because 2 isn't less than or equal to 1
- 비교 연산자는 보통 if 문과 같이 조건문과 함께 사용된다. 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".
- 두개의 tuple 이 동일한 type과 동일한 수의 값을 갖는다면 서로 비교할 수 있다.
- 비교 연산이 두 가지의 값이 동일하지 않다는 것을 발견할 때까지 tuple의 좌측 요소부터 우측으로 한 번에 하나의 값씩 비교해나간다.
- 두 값을 비교한 결과가 tuple 전체의 비교 결괏값이 된다.
- 다시 말해 tuple의 모든 요소가 동일하면 두 tuple은 동일하다고 판정된다.
(1, "zebra") < (2, "apple") // true because 1 is less than 2 "zebra" and "apple" aren't 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"
- 위 예시처럼 첫 줄에서의 let-to-right 비교 작업을 확인할 수 있다.
- 1이 2보다 작기 때문에 다른 값과 상관없이 (1, "zebra")는 (2, "apple") 보다 작다고 판단된다.
- 첫 번째 요소에 의해 비교값이 결정되었기 때문에 "zebra" 가 "apple" 보다 작은 것은 고려되지 않는다는 점이다.
- 만약 tuple의 첫번째 요소가 동일하다면 두 번째 요소를 비교하게 되며 위 코드의 두번째 줄에서 확인할 수 있다.
("blue", -1) < ("purple", 1) // OK, evaluates to true
("blue", false) < ("purple", true) // Error because < can't compare Boolean values
- tuple은 각 tuple의 각 value 값에 연산자를 적용할 수 있을 때에만 비교될 수 있다.
- 위 코드의 첫 줄은 String과 Int 전부 < 연산자로 비교할 수 있기 때문에 두 개의 tuple 또한 비교할 수 있다.
- 반면에 두 번째 줄에서 boolean 값은 < 연산자를 적용할 수 없기 때문에 두 개의 tuple 또한 비교할 수 없다.
Note
The Swift standard library는 원소가 7개보다 적은 tuple에 대한 비교 연산자를 포함하고 있습니다. 7개 이상의 원소를 갖는 tuple을 비교하려면 반드시 비교 연산자를 따로 구현해줘야 합니다.
Ternary Conditional Operator
- 삼항 조건 연산자 (ternary conditional operator)은 3가지 부분으로 나뉜 특별한 연산자이다.
- 형태는 question ? answer1 : answer2 이다.
- question의 진리값에 따라 두 개의 표현식 중 하나를 실행시키는 짧은 구문 (shortcut)이다.
- 만약 question이 true일 때 answer1을 실행하고 해당 값을 리턴한다.
- 만약 question이 false일 때 answer2를 실행하고 해당 값을 리턴한다.
- 다음과 같은 코드의 줄임 표현이다.
if question {
answer1
} else {
answer2
}
- 다음의 코드는 표의 행 높이를 계산하는 예시이다.
- 해당 행이 header일 때 콘텐츠의 높이보다 50pt 길게 설정한다.
- 해당 행이 header가 아니라면 콘텐츠의 높아보다 20pt 길게 설정한다.
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight is equal to 90
- 위 코드는 다음 코드의 축약형이다.
let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
rowHeight = contentHeight + 50
} else {
rowHeight = contentHeight + 20
}
// rowHeight is equal to 90
- 첫 번째 예시에서 삼항 조건 연산자(ternary conditional operator)를 사용하는 것의 의미는 다음과 같다.
- rowHeight은 한 줄의 코드를 통해 알맞은 값으로 설정될 수 있어서 두 번째 예시보다 더 간결하게 표현된다.
- 삼항 조건 연산자는 고려해야 할 두 가지 표현식을 결정하는 효율적인 축약성을 제공한다.
- 하지만 삼항 조건 연산자는 조심스럽게 사용해야 한다.
- 이 코드가 과도하게 사용될 경우 간결함 때문에 코드를 읽기 어려워질 수 있기 때문이다.
- 축약형 표현에 여러 개의 삼항 조건 연산자를 함께 사용하는 것을 하지 말아야 한다.
Nil-Coalescing Operator
- nil-coalescing(합치기) operator 는 ( a ?? b ) 으로 사용된다.
- optional a가 값을 갖고 있다면 optional을 벗겨(unwrap)낸다.
- optional a가 값을 갖고 있지 안다면 즉, a가 nil 상태라면 기본값 b를 리턴한다.
- 표현식(expression) a는 언제나 optional 타입이며 표현식 b는 a에 내부에 저장된 값의 type과 반드시 일치해야한다.
- nil-coalescing 연산자는 다음과 같은 코드의 축약형이다.
a != nil ? a! : b
- 위 코드는 삼항 조건 연산자를 사용했으며 a가 nil이 아닐 때 a 내부의 값에 접근하기 위해 forced unwrapping(a!)를 사용했다.
- nil-colescing 연산자는 위와 같은 conditional check와 unwrapping을 encapsulate하여 간결하고 읽기좋은 형태를 구현했다.
Note
만약 a의 값이 nil이 아니라면 b의 값은 실행되지 않으며 short-circuit evaluation으로 알려져 있습니다.
- 다음의 코드는 color 이름의 기본값과 사용자 정의 컬러 이름 중에서 선택하기 위해 nil-coalescing 연산자를 사용한 예시이다.
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"
- userDefinedColorName 변수는 optional String으로 정의되어있으며 기본값 nil을 갖고있다.
- 따라서 value 값을 결정하기위해 nil-coalescing 연산자를 사용할 수 있다.
- 위 예시에서는 colorNameToUse라고 불리는 String 변수의 초기값을 결정하는데 nil-coalescing 연산자를 사용하고 있다.
- userDefinedColorName의 상태에 따라 colorName에 해당값이 저장되거나 기본 컬러이름인 "red"가 저장된다.
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName isn't nil, so colorNameToUse is set to "green"
- userDefinedColorName이 nil이 아닌 값이 할당한 후에 nil-coalescing 연산자를 적용하면 defaultColorName이 아닌 userDefinedColorName이 항상 사용된다.
Range Operators
- Swift는 몇가지 범위 연산자를 제공하며 값의 범위를 축약하여 표현해준다.
Closed Range Operator
- 닫힌 범위 연산자 (The closed range operator)는 ( a...b ) 형식으로 정의된다.
- a 부터 b 까지의 범위를 정의하며 값 a와 b를 포함하고 있다.
- a의 값이 반드시 b보다 크면 안된다.
- for-in과 같은 반복문에서 어느 범위의 모든 값을 사용해야 할 때 유용하다. for-loop에 대한 자세한 정보 Control Flow
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
- half-open range operator 는 ( a..<b ) 형식으로 정의된다.
- a부터 b까지의 범위를 정의하며 a는 포함하지만 b는 제외된다.
- 배열과 같이 0부터 시작하는 리스트에 접근할 때 유용하다.
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
- 폐쇄 범위 연산자(The closed range operator)는 가능한 한 방향으로 지속되는 범위에 대한 대체 표현이 있다.
- 예를들어 인덱스 2부터 배열의 끝 요소까지 표현할 수 있는 범위를 표현할 수 있다.
- 범위 연산자의 한쪽 값을 생략하는 방식으로 구현할 수 있다.
for name in names[2...] {
print(name)
}
// Brian
// Jack
for name in names[...2] {
print(name)
}
// Anna
// Alex
// Brian
- half-open range operator 또한 마지막 값만을 적어줌으로써 one-sided form 형태를 갖고 있다.
- 마지막 값이 범위에 포함되지 않는다.
for name in names[..<2] {
print(name)
}
// Anna
// Alex
- One-sided ranges는 subscript가 아닌 다른 contexts 에서도 사용될 수 있다.
- 첫번째 값을 생략한 one-sided range에서는 반복의 시작 지점이 명확하지 않기 때문이다.
- 마지막 값을 생락한 one-sided range에서는 반복을 사용할 수 있지만 범위가 무한정 지속되기 때문에 종료 조건을 가져야 한다.
- 다음의 코드를 통해 값의 포함 여부를 확인할 수 있다.
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
Logical Operators
- 논리 연산자 (Logical operators)는 true와 false로 이루어진 Boolean 논리값을 수정(modify)하거나 결합(combine)시켜준다.
- Swift는 C기반 언어에서 찾아볼 수 있는 3가지 표준 논리 연산자를 제공한다.
- Logical NOT (!a)
- Logical AND (a && b)
- Logical OR (a || b)
Logical NOT Operator
- NOT 논리 연산자는 !a 의 형태로 사용되며 Boolean 값에 대해 true는 false, false는 true로 뒤집어(invert)준다.
- 논리적 NOT 연산자는 prefix 연산자이기 때문에 사용될 value값의 바로 앞쪽에서 공백없이 사용된다.
- not a의 형태로 읽을 수 있다.
let allowedEntry = false
if !allowdEntry {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
Logical AND Operator
- AND 논리 연산자는 a && b의 형태로 사용되며 두 값이 모두 true여야지만 true를 반환한다
- 어느 하나라도 false라면 false를 반환한다.
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
Logical OR Operator
- OR 논리 연산자는 a || b 형태로 사용되며 두개의 pipe 문자로 구성되어있다.
- 두개의 값 중에서 어느 하나라도 true 값을 갖고 있다면 true를 반환한다.
- AND 연산자처럼 OR연산자도 short-circuit-evaluation을 사용하기 때문에 좌측 부분에서 하나라도 true를 찾는다면 나머지 부분은 계산해보지도 않는다.
- 전체 표현식의 계산 결과에 영향을 주지 않기 때문이다.
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
Combining Logical Operators
- 긴 복합 표현식을 생성하기 위해 여러개의 논리 연산자를 결합할 수 있다.
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
- 여러개의 &&와 || 연산자를 사용해서 긴 복합 표현식을 작성한 코드이다.
- 그럼에도 논리연산자는 두개의 operator만 사용되기 때문에 3개의 작은 표현들이 합쳐진 형태로 구현된다.
- 만약 알맞은 비밀번호를 입력했고 홍체인식을 통과하였다면 잠금 해제
- 전 단계를 통과하지 못하였을 때 door key를 갖고 있어도 잠금 해제
- 전 단계를 통과하지 못하였을 때 knowsOverridePassword를 갖고 있어도 잠금 해제
Note
Swift 논리 연산자 && 및 || 는 left-associative 합니다. 즉, 여러개의 논리 연산자가 합성된 표현식이 있을 때 가장 좌측의 부분 부분 표현식부터 확인해나갑니다.
Explicit Parentheses
- 명시적 괄호는 (explicit parentheses) 복잡한 표현식을 읽기 쉽게 만드는 용도로 사용한다.
- 위에서 사용된 Door Access 예시에서 첫번째 논리 연산자에 괄호를 추가하여 의도를 명확히 할 수 있다.
- 가독성은 간결함보다 더 우선시 된다.
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
반응형
' Apple > Swift Programming Language' 카테고리의 다른 글
[Swift] 공식문서 씹어먹기: Collection Type - Dictionary (0) | 2021.10.22 |
---|---|
[Swift] 공식문서 씹어먹기: Initialization (0) | 2021.10.18 |
[Swift] 공식문서 씹어먹기: Strings and Characters (0) | 2021.09.23 |
[Swift] 공식문서 씹어먹기: The Basics (0) | 2021.09.19 |
Swift 코딩 시행 착오 저장소 (0) | 2021.09.07 |