 Apple Lover Developer & Artist

영속적인 디자인에 현대의 공감을 채워넣는 공방입니다

 Apple/Swift Programming Language

[Swift] 공식문서 씹어먹기: Basic Operators

singularis7 2021. 9. 21. 10:54
반응형

Swift Logo

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!"

 

반응형