기본
Syntax
A + B
A와 B는 Operend (피연산자)
+는 Operend (연산자)
구분
+A | A + B | A + B : C |
단항연산자 | 이항연산자 | 삼항연산자 조건연산자 |
//단항연산자는 공백 없이 붙여 쓴다.
//⭕️
+A
//❌
+ A
//이항연산자는 공백을 사용해 띄어 쓴다.
//⭕️
A + B
//❌
A+B
//연산자 형식에 따른 명칭
//prefix Operator
+A
//postfix Operator
A+
//infix Operator
A + B
기본적으로 곱과 나눗셈을 덧셈과 뺄셈보다 우선 수행한다.
Arithmetic Operator (산술 연산자)
Addiction (덧셈)
Syntax
A + B
Subtraction (뺄셈)
Syntax
A - B
Multiple (곱셈)
Syntax
A * B
Division (나눗셈)
Syntax
A / B
Reminder, Modulo (나머지)
Syntax
A % B
floating point 간의 연산은 지원하지 않는다.
이 경우 truncatingReminder를 사용한다.
Syntax
A.truncatingReminder(dividingBy: B)
Overflow Operator (오버플로우)
Swift에선 Overflow를 기본적으로 허용하지 않는다.
따라서 결과를 예측할 수 없는 경우 무리하지 말고 큰 자료형을 사용하자.
단, 의도적으로 사용하고 싶은 경우 Overflow 연산자를 사용해야 한다.
Overflow Addiction Operator (오버플로우 덧셈)
Syntax
A &+ B
let a: Int8 = Int8.max
let b: Int8 = a &+ 1
print(b)
b의 값은 -128이다.
Overflow Subtraction Operator (오버플로우 뺄셈)
Syntax
A &- B
let a: Int8 = Int8.min
let b: Int8 = a &- 1
print(b)
b의 값은 127이다.
Overflow Multiplication Operator (오버플로우 곱셈)
Syntax
A &* B
let a: Int8 = Int8.max
let b: Int8 = a &* 2
print(b)
b의 값은 -2이다.
왜?
Int8의 저장 범위는 '-128 ~ 127' 이다.
따라서 Int8.max의 값은 '127'이고, 2진수로 변경하면 다음과 같다.
SB | 64 | 32 | 16 | 8 | 4 | 2 | 0 | |
a | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
'a &* 2'의 연산은 다음과 같이 진행된다.
SB | 64 | 32 | 16 | 8 | 4 | 2 | 0 | |
a | 0 | 1 | 1 | 1 | 1 | 1 | 1 | |
a | 0 | 1 | 1 | 1 | 1 | 1 | 1 | |
b | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
b는 SignBit가 1이므로 음수이고, 나머지 Bit를 2의 보수화 하면 2이다.
따라서 'a &* 2'의 결과는 '-2' 이다.
Comparison Operator (비교 연산자)
Equal to Operator
Syntax
A == B
Not Equal to Operator
Syntax
A != B
Grater than Operator
Syntax
A > B
Greater than or Equal Operator
Syntax
A >= B
Less than Operator
Syntax
A < B
Less than or Equal Operator
Syntax
A <= B
Logical Operator (논리 연산자)
Logical NOT Operator
Syntax
!A
입력 | 출력 |
true | false |
false | true |
Logical AND Operator
Syntax
A && B
입력A | 입력B | 출력 |
true | ture | true |
true | false | flase |
false | true | false |
false | false | false |
Logical OR Operator
Syntax
A || B
입력A | 입력B | 출력 |
true | ture | true |
true | false | true |
false | true | true |
false | false | false |
Ternary Conditional Operator (조건 연산자)
Syntax
Condition ? expr1 : expr2
Condition1 ? expr1 : (Condition2 ? expr2 : expr3)
조건 연산자의 경우 if나 switch로 대체가 가능하다.
2번과 같이 조건이 많아지는 경우 코드의 가독성이 나빠지기 때문에 이를 활용한다.
//if로 구현하기
if Condition1 {
expr1
} else {
if Condition2 {
expr2
} else {
expr3
}
}
//switch로 구현하기
switch {
case Condition1:
expr1
case Condition2:
expr2
default:
expr3
}
조금 길어 보여도 명확하다.
Short Circuit Evaluation
Swift는 논리식을 평가할 때 필요한 최소한의 연산만 수행한다.
Logical And Operator
입력A | 입력B | 출력 |
true | ture | true |
true | false | flase |
false | true | false |
false | false | false |
And 연산은 좌변이 false이면 항상 false이다.
Logical Or Operator
입력A | 입력B | 출력 |
true | ture | true |
true | false | true |
false | true | true |
false | false | false |
Or 연산은 좌변이 true인 경우 항상 true이다.
이렇게 좌변 만으로 결과가 도출 되는 경우 우변은 수행하지 않고 논리식을 평가한다.
이 연산 속도 면에서 상당한 이득이지만 다음과 같은 경우 문제가 되기도 한다.
var a = 1
var b = 1
func inputA() -> Bool {
a += 1
return false
}
func inputB() -> Bool {
b += 1
return true
}
if inputA && inputB {
}
print(a)
print(b)
결과
2
1
이 경우 좌변인 inputA의 결과가 flase이기 때문에 inputB는 실행되지 않는다.
따라서 결과는 a=2, b=1 이다
만약 'a+b'의 연산을 추가적으로 수행하고자 한다면 3의 결과가 나오므로 일반적이지 않다.
var a = 1
var b = 1
func updatedLeft() -> Bool {
a += 1
return false
}
func updatedRight() -> Bool {
b += 1
return true
}
let resultA = updatedLeft()
let resultB = updatedRight()
if resultA && resultB {
}
print(a)
print(b)
결과
2
2
이렇게 inputA와 inputB를 먼저 실행하고 논리식을 진행하면
결과는 a=2, b=2가 되고, 비로소 'a+b'를 추가적으로 수행했을 때 4라는 일반적인 결과가 된다.
이렇게 코드를 실행했을 때 값이나 상태가 변하는 것을 'Side effect'라고 한다.
직역하면 '부작용'의 의미이지만 프로그래밍에선 마냥 부정적인 의미는 아니다.
논리식을 다룰 땐 이 'Side effect'를 염두해 두고 논리식 내에서의 side effect를 최소화 하는 것이 좋다.
Bitwise Operator
Bitwise Not Operator
Syntax
~A
A | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 |
0과 1을 바꾼다
Bitwise And Operator
Syntax
A & B
A | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
B | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
모두 1이면 1이다.
Bitwise Or Operator
Syntax
A | B
A | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
B | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 |
둘 중 하나라도 1이면 1이다.
Bitwise XOr Operator
Syntax
A ^ B
A | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
B | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 |
둘 중 하나만 1이면 1이다.
Bitwise Left Shift Operator
Syntax
A << n
한 비트 옮길 수록 2배씩 커진다.
곱 연산보다 연산속도가 빠르지만 차이가 미비하다.
Logical Shift
A | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | ||
0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 |
왼쪽으로 한 비트씩 옮긴다.
Bitwise Right Shift Operator
Syntax
A >> n
한 비트 옮길 때 마다 1/2이 된다.
LogicalShift
A | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | ||
0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
오른쪽으로 한 비트씩 옮긴다.
Arithmetic Shift
A | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | ||
1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
단, SignBit를 가졌을 경우 0이 아닌 원래의 SignBit를 채운다.
Assigment Operator
Syntax
A = B
할당 연산자는 값을 반환하지 않는다.
Compound Assigment Operator
Addiction Assigment Operator
Syntax
A += B
A = A + B
Subtraction Assigment Operator
Syntax
A -= B
A = A - B
Multiplication Assigment Operator
Syntax
A *= B
A = A * B
Division Assigment Operator
Syntax
A /= B
A = A / B
Modulo Assigment Operator
Syntax
A %= B
A =A % B
Bitwise AND Assigment Operator
Syntax
A &= B
A = A & B
Bitwise OR Assignment Operator
Syntax
A |= B
A = A | B
Bitwise XOR Assignment Operator
Syntax
A ^= B
A = A ^ B
Bitwise Left Shift Assginment Operator
Syntax
A <<= B
A = A << B
Bitwise Right Shift Assginment Operator
Syntax
A >>= B
A = A >> B
Range Operator
Closed Range Operator
Syntax
A ... B
A...
...A
let list = [1, 2, 3, 4, 5]
//[3, 4]
list[2 ... 3]
//[3, 4, 5]
list[2...]
//1, 2, 3, 4]
list[...3]
index로 접근하기 때문에 시작이 1이 아닌 0임을 유의하자.
Half-open Range Operator
Syntax
A ..< B
..<A
let list = [1, 2, 3, 4, 5]
//[1, 2]
list[..<2]
//[1, 2, 3]
list[0 ..< 3 ]
Operator methods
연산자를 새로 생성하는 게 아닌 기존 연산자의 확장이다.
Syntax
static func operator(parameters) -> ReturnType {
statemnets
}
Operator methods는 연산자가 가지고 있는 결합규칙과 우선순위를 바꾸지 않는다.
가능한한 원래의 기능과 동일하거나 유사한 형태로 구현해야 한다.
그러지 않을 경우 코드의 가독성이 떨어지고 논리적 오류가 발생할 가능성이 커진다.
//Double 두 개 짜리 구조체 생성
struct Point {
var x = 0.0
var y = 0.0
}
let p1 = Point(x: 10, y: 100)
let p2 = Point(x: 20, y: 50)
//p1 == p2 -> error
//구조체를 비교하는 방법 선언
extension Point: Equatable {
static func ==(lhs: Point, rhs: Point) -> Bool {
return (lhs.x == rhs.x) && (lhs.y == rhs.y)
}
}
구조체에서 생성해도 되지만, 보통은 Extension으로 구현한다.
다만 위의 Operator method는 다음과 같이 단축 되기도 한다.
extension Point: Equatable {
//static func ==(lhs: Point, rhs: Point) -> Bool {
// return (lhs.x == rhs.x) && (lhs.y == rhs.y)
}
}
구조체의 자료형이 동일하고, 해당 자료형이 동일한 Equatable protocol을 사용하는 경우 컴파일러가 자동으로 구현하기도 한다.
//구조체 부호 변경 구현하기
extension Point {
static prefix func -(pt: Point) -> Point { //단항연산자의 경우 연산자의 위치를 선언해 줘야 한다.
return Point(x: -pt.x, y: -pt.y)
}
}
//구조체 증가 연산자 구현
extension Point {
static postfix func ++(pt: inout Point) -> Point{ //단항연산자의 경우 연산자의 위치를 선언해 줘야 한다.
let ret = pt
pt.x += 1
pt.y += 1
return ret
}
}
'++'의 구현의 경우 값을 변경해야 하기 때문에 inout prameter를 사용해야 한다.
Custom Operator
첫번째로 조합해야 하는 기호
/, =, -, +, !, *, %, <, >. &, |, ^, ? ~
단독사용 불가능한 기호
( ), { }, [ ], ".", ",", :, ;, =, @, #, &, ->, ₩, ?, !
연산자 선언하기 (반드시 global scope에서 선언해야 한다.)
Syntax
prefix operator ▢
postfix operator ▢
infix operator ▢
//prefix
▢A
//postfix
A▢
//infix
A ▢ B
연산자는 가능한 간단한 형태로 선언할 것.
기족 연산자와 모호함이 없도록 선언할 것.
사용 예시
prefix operator +++
extension Int {
static prefix func +++(num: inout Int) {
num += 100
}
}
var a = 1
+++a
결과
101
Precedence Groups (우선순위 그룹)
Syntax
infixs operator operator: PrecenenceGroup
precedencegroup Name {
higherThan: lowerGroupName
lowerThan: HigherGroupName
associativity: left, right, none
}
우선순위는 ':'뒤에 기입하는 것에 대한 조건임을 기억해야 한다.
Swift에서 지원하는 기본 연산자들의 우선순위 그룹은 다음과 같다.
Operators | Precedence Groups |
+, - | AddictionPrecednece |
*, / | MultiplicationPrecedence |
<, <=, >, >=, ==, != | ComparisonPrecedence |
=, +=, -=, *=, /= | AssignmentPrecedence |
precedencegroup Myprecedence {
higherThan: AdditionPrecedence
}
infix operator *+*: Myprecedence
extension Int {
static func *+* (left: Int, right: Int) -> Int {
return (left * right) + (left * right)
}
}
1 *+* 2 + 3
결과
7
우선순위 그룹의 method는 최소 하나는 작성해야 한다.
배운 것을 바탕으로 '+='를 구현해 보자
//Double 두 개 짜리 구조체 생성
struct Point {
var x = 0.0
var y = 0.0
}
//'+=' 구현
extension Point {
static func +=(lhs: inout Point, rhs: inout Point) ->Point { //값을 변경하여 다시 전달해야 하기 때문에 inout parameter 사용
lhs.x += rhs.x
lhs.y += rhs.y
return Point(x: lhs.x, y: rhs.y)
}
}
var p6 = Point(x: 10, y: 20)
var p7 = Point(x: 1, y: 1)
p6 += p7
p6.x
p6.y
p7.x
p7.y
결과
11
21
1
1
Log
2021.08.04.
블로그 이전으로 인한 글 옮김 및 수정
'학습 노트 > Swift (2021)' 카테고리의 다른 글
037 ~ 038. Loop Statements (반복문) (0) | 2021.08.06 |
---|---|
032 ~ 036. Conditional Statements (조건문) (0) | 2021.08.06 |
012 ~ 019. literal과 datatype (0) | 2021.08.01 |
009 ~ 011. 변수와 상수 생성하기, Scope (0) | 2021.08.01 |
001 ~ 008. 기본 용어, 특수문자 (0) | 2021.07.28 |