아요 개발 일기

[Swift] 기본 연산자 (Basic Operator) 본문

Swift/The Swift Programming language

[Swift] 기본 연산자 (Basic Operator)

소진이 2022. 12. 30. 11:49

안녕하세요!~ :-D

오늘은 swift언어의 기본 연산자에 대하여 알아보도록하겠습니다!

이 글은 The Swift Language Guide를 기반으로 작성되었습니다 :0

 


기본 연산자 (Basic Operators)란?

 

연산자는 값을 확인하거나 변경 또는 결합할 때 사용하는 특수 기호 또는 구문입니다.

 

Swift에서는 통상적으로 C언어에서 사용하는 +, - , / , % 같은 산술 연산자와 &&,|| 같은 논리 연산자를 지원하며,

 이외에도 a..<b나 a...b와같은 범위 연산자도 지원합니다!


Terminology (용어)

 

연산자에는 단항(unary) 이항(binary), 그리고 삼항 연산자(ternary)가 있습니다.

 

  • 단항 연산자 : -a , !b , c! 와 같이 대상의 바로 앞이나 뒤에 붙여 사용하는 연산자
  • 이항 연산자 : 2 + 3 과 같이 두 개의 대상의 사이에 있는 연산자
  • 삼항 연산자 : a ? b : c 와 같은 형태의 조건부 연산자 (Swift에서 삼항 연산자는 이 연산자 하나 뿐입니다!)

Assignment Operator (할당 연산자)

할당 연산자는 초기화하거나 값을 업데이트(변경)를 합니다. 

상수, 변수 모두에서 사용 가능합니다.

 

let b = 10
var a = 5
a = b
// a 의 값은 10

 

아래와 같이 튜플을 이용해 여러 값을 한 번에 할당 할 수 있습니다.

 

let (x,y) = (1,2)
// x = 1, y = 2

 

C 및 Objective-C의 할당 연산자와 달리 Swift의 할당 연산자 자체는 값을 반환하지 않습니다. 

그래서 아래 코드는 유효하지 않습니다!

 

if x = y {
    //  x= y 는 값을 반환하지 않기 때문에 올바르지 않은 문법
}

 

Q. 할당 연산자가 값을 반환하지 않는 이유가 뭐에요??

A. 동등 비교 연산자(==)를 사용해야하는 곳에 할당 연산자(=)가 실수로 사용되는 경우를 방지하기 위해서 사용됩니다. (오류 방지!!)


Arithmetic Operators ( 산술 연산자)

Swift는 모든 숫자 타입에 아래와 같은 사칙 연산자를 제공합니다.

  • 덧셈 (+)
  • 뺄셈 (-)
  • 곱셈 (*)
  • 나눗셈 (/)

 

1 + 2        // 3
5 - 3        // 2
2 * 3        // 6
10.0 / 2.5   // 4.0

 

C와 Objective-C의 산술 연산자와는 다르게 Swift 산술 연산자는 오버플로우를 허용하지 않습니다.

하지만 Swift의 오버플로우 연산자 (예 : a &+ b)를 사용하면 허용 될 수 있습니다. 

 

덧셈 연산자는 아래와 같이 문자열을 합치기 위해 사용할 수 있습니다.

 

"hello, " + "world"  // "hello, world"

 

Remainder Operator (나머지 연산자)

a % b 형식으로, 나머지를 구하는 연산자입니다.

 

나머지 연산자(%)가 다른 언어에서는 모듈화 연산자로도 알려져 있습니다.
그러나 Swift에서 음수에 대한 계산은 모듈화 작업이 아니라 나머지라는 것을 의미합니다!

 

아래와 같이 음수값에 대한 계산도 동일한 방법이 적용됩니다.

 

9 % 4    // 1
-9 % 4   // -1

 

Unary Minus Operator (단항 음수 연산자)

- 부호를 값 바로 앞에 추가하여 사용합니다.

음수 값은 단항 음수 연산자에 의해 부호가 +로 변합니다.

 

let three = 3
let minusThree = -three       // minusThree = -3
let plusThree = -minusThree   // plusThree = 3, or "minus minus 3"

 

Unary Plus Operator (단항 양수 연산자)

+ 부호를 값 바로 앞에 추가하여 사용합니다.

단항 양수 연산자는 아무런 수행을 하지 않습니다. 

 

Q. ?? 그럼 굳이 단항 양수 연산사를 왜 사용해요?

A. 단항 음수 연산자를 사용하는 경우 코드에서 대칭성을 제공하기 위함입니다!

 

let minusSix = -6
let alsoMinusSix = +minusSix  // alsoMinusSix = -6

 


Compound Assignment Operators (복합/합성 할당 연산자)

a = a + 2와 같은 식의  할당 연산(=) 덧셈 연산(+)을 결합하여 += 형태로 축약해 사용합니다.

 

var a = 1
a += 2
// a = 3

 

복합 할당 연산자는 값을 반환하지 않습니다.
즉, let b = a+=2 와 같은 문법은 사용할 수 없습니다.

더 많은 정보는 연산자 선언(Operator Declarations) 에서 확인할 수 있습니다.


Comparison Operators (비교 연산자)

  • 같다 (a == b)
  • 같지 않다 (a != b)
  • 크다 (a > b)
  • 작다 (a < b)
  • 크거나 작다 (a >= b)
  • 작거나 같다 (a <= b)
Swift는 객체 비교를 위해 식별 연산자 ===와 !==를 제공합니다.

비교 연산은 true 또는 false 값을 반환합니다.

 

1 == 1   // true
2 != 1   // true
2 > 1    // true
1 < 2    // true
1 >= 1   // true
2 <= 1   // false

 

비교 연산자는 아래와 같은 if-else 조건문에서 자주 사용됩니다.

 

let name = "world"
if name == "world" {
    print("hello, world")
} else {
    print("I'm sorry \(name), but I don't recognize you")
}
// 결과 : "hello, world" (name = "world"로 일치하기때문에)

if문과 관련한 더 많은 정보는 제어문 (Control Flow) 에서 확인할 수 있습니다.

 

값의 타입과 개수가 동일한 경우 두개의 튜플을 비교할 수 있습니다.

튜플 비교는 왼쪽에서 오른쪽 방향으로 이루어지고 한 번에 하나씩 비교됩니다. 

이 비교는 다른 두 값을 비교하게 될 때까지 수행합니다.

 

(1, "zebra") < (2, "apple")   // true ; 1이 2보다 작고, zebra와 apple은 비교하지 않음
(3, "apple") < (3, "bird")    // true ; 왼쪽 3과 오른쪽 3이 같고, apple은 bird보다 작음
(4, "dog") == (4, "dog")      // true ; 왼쪽 4는 오른쪽 4와 같고, 왼쪽 dog는 오른쪽 dog와 같음

 

첫 번째 줄의 코드는 1과 2가 같지 않기 때문에 문자를 비교하지 않고 비교는 종료 됩니다.

하지만, 두 번째와 세 번째 줄의 튜플은 3과 4의 숫자를 비교하는 튜플의 값이 각각 같기 때문에 문자까지 비교하게 됩니다.

 

Boolean 값은 비교연산자가 비교를 수행 할 수 없기때문에 아래와 같이 에러가 뜹니다.

 

("blue", -1) < ("purple", 1)        // 비교가능, 결과 : true
("blue", false) < ("purple", true)  // 에러, Boolean 값은 < 연산자로 비교할 수 없기 때문에

 

Swift 표준 라이브러리에서는 7개 요소 미만을 갖는 튜플만 비교할 수 있습니다. 만약 7개 혹은 그 이상의 요소를 갖는 튜플을 비교하고 싶으면 직접 비교 연산자를 구현해야 합니다.

삼항 조건 연산자(Ternary Condirional Operator)

삼항 조건 연산자는 question ? answer1 : answer2 형식을 사용합니다. 질문(question)이 참인경우 answer1이 거짓인 경우 answer2가 실행됩니다. 삼항 조건 연산자는 아래와 같은 if-else문의 축약 연산자 입니다.

 

if question {
    answer1
} else {
    answer2
}

 

실제 사용 예시입니다.

 

let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight = 90 (40 + 50)

 

위의 코드를 아래와 같이 풀어 쓸 수 있습니다.

 

let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
    rowHeight = contentHeight + 50
} else {
    rowHeight = contentHeight + 20
}
// rowHeight = 90

 

삼항 조건 연산은 코드를 짧게 만들어 가독성을 높여줍니다.

하지만 삼항 조건 연산자을 과도하게 사용할 경우 오히려 읽기 어려운 코드로 이어질 수 있기때문에 사용을 주의하여야 합니다.


Nil-Coalescing Operator(Nil 병합 연산자)

nill 병합 연산자는 a ?? b 형식을 갖는 연산자입니다.

a의 값이 nil이 아닌경우 옵셔널 a를 반환하고 a가 nil 인 경우 b를 반환합니다. 이 nil 병합 연산자는 아래의 코드의 축약형입니다.

 

a != nil ? a! : b

 

이제 예시를 함께 보면서 이해해 보겠습니다.

 

let defaultColorName = "red"
var userDefinedColorName: String?   // 이 값은 nil

var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName이 nil이므로 colorNameToUse 값은 defaultColorName인 "red"로 설정 됩니다.

 

위의 코드의 결과 값은 red입니다. 만약 설명이 잘 이해가지 않는다면,

Nil 병합 연산자(userDefinedColorName ?? defaultColorName)를 앞에서 배운 삼항 연산자를 이용하여 쉽게 표현해보았습니다!

 

userDefinedColorName != nil ? userDefinedColorName! : defaultColorName

 

이 코드는 풀이는

 

userDefinedColorName이 nil값이 아니니?
--> 맞아!(nil값이 아님)= userDefinedColorName을 unwraps하여 반환
--> 아니야!(nil값) = defaultColorName값 반환

 

 

으로 볼 수 있습니다. userDefinedColorName값이 nil이므로 defaultColorName의 값인 red를 반환합니다.

 

 

다른 예시도 한 번 살펴보겠습니다.

userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName가 nil이 아니므로 colorNameToUse 는 "green"이 됩니다.

 

위의 코드는 userDefinedColorName이 nil 값이 아니므로 colorNameToUse의 값은 green이 되겠죠?


Range Operators (범위 연산자)

 

Closed Range Operator(닫힌 범위 연산자)

(a...b)의 형태로 a에서 b까지 실행되는 범위를 말합니다. (a와 b 포함)

for-in loop에서 자주 사용합니다.

 

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

for-in loop에 관한 더 많은 정보는 Control Flow에서 보실 수 있습니다.

 

Half Open Range Operator(반 닫힌 범위 연산자)

(a..<b)의 형태로 a부터 b보다 작을 때까지의 범위를 갖습니다. 즉, a부터 b-1까지 값을 갖습니다.

보통 배열의 크기는 -1의 인덱스를 갖기 때문에 이 반 닫힌 범위 연산자는 배열을 다루는데 유용합니다.

 

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

배열에 관해 더 많은 정보는 Arrays에서 보실 수 있습니다.

 

One-Sided Range(단방향 범위)

[a..][..a]의 형태로 범위의 시작 혹은 끝만 지정하여 한 방향으로 계속되는 값들에 사용하는 범위 연산자입니다.

지정한 a값(시작 값 혹은 끝 값)은 범위에 포함됩니다.

 

for name in names[2...] {
    print(name)
}
// Brian
// Jack

for name in names[...2] {
    print(name)
}
// Anna
// Alex
// Brian

 

단방향 범위 연산자는 앞서 설명한 반 닫힌 연산자와 비슷한 (..<a) 형식으로도 사용됩니다.

이 형식은 반 닫힌 연산자처럼 최종값(a)은 범위에 포함되지 않습니다.

 

for name in names[..<2] {
    print(name)
}
// Anna
// Alex

 

단방향 범위 연산자 중 시작 값이 생략된 형식(...a)인 경우에는 반복을 사용할 수 없습니다.

마지막 값이 생략된 형식(a...)은 반복은 가능하나, 무한대로 계속 되므로 루프에 대해 명시적 종료 조건을 추가해야 합니다.

 

하지만 단방향 범위 연산자는 아래 코드처럼 단방향 범위에 특정 값이 포함하는지의 여부를 확인할 때 사용이 가능합니다.

 

let range = ...5
range.contains(7)   // false
range.contains(4)   // true
range.contains(-1)  // true

Logical Operators(논리 연산자)

논리 연산자는 Boolean 논리 값을 true와 false로 수정하거나 결합합니다.

Swift는 C 기반 언어로 세가지 표준 논리 연산자를 지원합니다.

  • 논리 부정 NOT (!a)
  • 논리 곱 AND (a && b)
  • 논리 합 OR (a || b)

 

Logical NoT Operator (논리 부정 연산자)

논리 부정 연산자는 접두사 연산자로, !을 값 바로 앞에 붙이는 형식을 사용합니다.

부울 값을 반전시키며 아래 예시에서 볼 수 있듯이 "not a"로 읽을 수 있습니다.

 

let allowedEntry = false
if !allowedEntry {
    print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"

 

위의 예시의  !allowedEntry 구문은 "허용되지 않은 경우"로 읽을 수 있습니다.

다음 행은  "허용되지 않은 항목"이 true인 경우에만 실행됩니다. 즉, allowedEntry가 false인 경우에만 실행됩니다.

 

위 예와 같이 Bool 상수 및 변수 이름을 주의 깊게 선택하면 코드를 간결하게 읽을 수 있고 간결하게 유지하는 동시에 이중 부정 또는 혼동되는 논리 문장을 피할 수 있습니다.

 

Logical AND Operator (논리 곱 연산자)

(a&b)의 형식을 사용하며, 결과 값이 참이 되려면 두 값이 모두 참이여야하는 연산자입니다.

true & false = false / false & false = false / true & true = true

실제로 첫 번째 값이 거짓이면 두 번째 값은 평가되지 않습니다.(하나라도 거짓이면 참이될 수 없기때문에) 이를 단락 평가라고 합니다.

 

아래 예시는 두개의 Bool 값을 고려하여 두 값이 모두 참인 경우에만 액세스를 허용하는 코드 입니다.

 

let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"

 

Logical OR Operator (논리 합 연산자)

(a||b)형식을 사용하며, 결과 값이 참이 되려면 두 값 중 하나만 참이여도 되는 연산자입니다.

 

위의 논리 AND 연산자와 마찬가지로 OR 연산자는 단락 평가를 사용하여 표현식을 고려합니다.

논리 OR 식의 왼쪽이 참이면 오른쪽은 평가에 영향을 주지 않으므로 오른쪽은 평가되지않습니다.

아래 예제는 첫 번째 Bool 값(hasDoorKey)은 false이지만 두 번째 값(KnowsOverridePassword)은 true입니다.

OR 연산자는 두 개의 값 중 하나만 참이 되면 결과 값도 참이되므로 액세스가 허용된다는 메세지를 출력하게됩니다.

 

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

위의 예제는 if 문을 다음과 같이 해석할 수 있습니다.

 

올바른 도어코드를 입력(enteredDoorCode) 하고 (&&) 망막 스캔(passedRetinaScan)을 통과 했거나 (||) 유효한 도어 키가 있(hasDoorKey)거나 (||) 비상 오버라이드 암호를 알고있다면(knowsOverridePassword) 접근을 허용하세요.

 

위에 코드를 보면 각각의 값들이

enteredDoorCode = true , passedRerinaScan = false , hasDoorKey = false , knowsOverridePassword = true

인 것을 알 수 있습니다.

 

true와 false를 이용한 논리 식을 만들어보면,

 

true && false || false || true = true

이됩니다. 그러므로 결과 값은 Welcome!이 출력됩니다.

 

Explicit Parentheses (명시적 괄호)

논리 연산자의 적용 우선 순위를 연산자에 맡기지 않고 명시적으로 괄호를 사용해 계산 순서를 지정할 수 있습니다.

 

if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}
// Prints "Welcome!"

 

위 처럼 괄호를 사용하면 가독성이 높아져 코드의 의도를 더 명확하게 하는데 도움이 됩니다.

 


 

명시적 괄호를 마지막으로 기본 연산자에 대한 글이 끝났습니다!

다음 글은 String and Characters (문자열과 문자)에 대해 알아보도록 하겠습니다 :-)

감사합니당;0