Swift의 연산자는 특정한 문자로 표현한 함수라고 할 수 있습니다. 연산자에 의해 연산되는 값의 수에 따라 단항, 이항, 삼항 등으로 구분하기도 하며, 연산자의 위치에 따라 전위, 중위, 호위 등으로 구분하기도 합니다.
연산자의 분류
분류 | 설명 | 예시 |
단항 연산자 | 피연산자가 한 개인 연산자 | !A |
이항 연산자 | 피연산자가 두 개인 연산자 | A + B |
삼항 연산자 | 피연산자가 세 개인 연산자 | A ? B : C |
전위 연산자 | 연산자가 피연산자 앞에 위치하는 연산자 | !A |
중위 연산자 | 연산자가 피연산자 사이에 위치하는 연산자 | A + B |
후위 연산자 | 연산자가 피연산자 뒤에 위치하는 연산자 | A! |
띄어쓰기와 연산자
Swift에서 띄어쓰기는 중요한 문법 중 하나입니다. 연산자의 위치가 중요하지만, 연산자의 앞과 뒤 중 어디에 공백이 있는지도 중요합니다. 예를 들어, A != B
와 A! = B
는 전혀 다른 의미입니다. 또, A > B? A : B
는 잘못된 사용법이며 물음표를 B에서 띄어 써야 합니다.
연산자의 종류
할당 연산자
값을 할당할 때 사용하는 연산자
연산자 | 부호 | 설명 |
할당(대입) 연산자 | A = B | A에 B의 값을 할당한다. 서로 다른 데이터 타입이라면 오류가 발생함 |
산술 (arithmetic) 연산
산술 연산자는 숫자들에 대해 더하기, 빼기, 나누기, 곱하기입니다. 더하기(+
), 빼기(-
), 나누기(/
), 곱하기(*
)로 우리가 생각하는 것과 같은 기호를 사용합니다.
연산자 | 부호 | 설명 |
더하기 연산자 | A + B | A와 B를 더한 값을 반환 |
빼기 연산자 | A - B | A에서 B를 뺀 값을 반환 |
곱하기 연산자 | A * B | A와 B를 곱한 값을 반환 |
나누기 연산자 | A / B | A를 B로 나눈 값을 반환 |
나머지 연산자 | A % B | A를 B로 나눈 나머지를 반환 |
사용하는 방법은 아래와 같습니다.
let firstScore = 12
let secondScore = 4
let total = firstScore + secondScore //16
let difference = firstScore - secondScore //8
let product = firstScore * secondScore //48
let divided = firstScore / secondScore //3
// 나누기 연산은 기존의 프로그래밍 언어와 같이 나머지나 소수점을 제외한 정수만 결괏값으로 반환
var result: Int = 5 / 3 // 1
result = 10 / 3 // 3
연산자 오버로딩(Operator overloading)
let meaningOfLife = 42
let doubleMeaning = 42 + 42 //84
문자열 + 문자열
let fakers = "서근의 " //서근의
let action = fakers + "개발노트" //서근의 개발노트
let firstHalf = ["포뇨", "하울"]
let secondHalf = ["소스케", "서근"]
let beatles = firstHalf + secondHalf //포뇨, 하울, 소스케, 서근
주의 : Swift는 유형이 안전한 언어이므로 유형을 혼합 할 수 없습니다. 예를 들어, String
에 Int
를 추가할 수 없습니다.
만약 var score
에 5를 더하고 싶다면 원하면 score = score + 5
로 쓸 수 있습니다. 하지만 더 간편한 방법이 있습니다.
score += 5
는 score = score + 5
와 같은 결과를 얻을 수 있습니다.
var score += 5
var score = score + 5
예시
var result = 21
result -= 11 //result = 10
var result = 100
result /= 10 //result = 10
잘못된 예시
let result = 2
result *= 5 //상수를 수정하려고 함
비교 연산자(Comparison operator)
Swift에는 비교를 수행하는 여러 연산자가 있으며, 이것은 수학에서 사용하는 것과 비슷합니다.
연산자 | 부호 | 설명 |
값이 같다 | A == B | A와 B가 같은 값인지 비교하여 불리언 값을 반환 |
값이 크거나 같다 | A >= B | A가 B보다 크거나 같은 값인지 비교하여 불리언 값을 반환 |
값이 작거나 같다 | A <= B | A가 B보다 작거나 같은 값인지 비교하여 불리언 값을 반환 |
값이 크다 | A > B | A가 B보다 큰 값인지 비교하여 불리언 값을 반환 |
값이 작다 | A < B | A가 B보다 작은 값인지 비교하여 불리언 값을 반환 |
값이 같지 않다 | A != B | A와 B가 다른 값인지 비교하여 불리언 값을 반환 |
참조가 같다 | A === B | A와 B가 참조(래퍼런스) 타입일 때 A와 B가 같은 인스턴스를 가리키는지 비교하여 불리언 값을 반환 |
참조가 같지 않다 | A !== B | A와 B가 참조(래퍼런스) 타입일 때 A와 B가 같지 않은 인스턴스를 가리키는지 비교하여 불리언 값을 반환 |
패턴 매치 | A ~= B | A와 B의 패턴이 매치되는지 확인하여 불리언 값을 반환 |
a...b Closed Range
a..<b b를 포함하지않는 Half Open Range
...b b까지 포함하는 범위
let firstScore = 6
let secondScore = 4
두 값이 같은지, 같지 않은지 확인하는 두 가지 연산자가 있습니다.
두 값이 같은 지 확인하는 ( == )
두 값이 같지 않은지 확인하는 ( != )
firstScore == secondScore
firstScore != secondScore
var name = "Seogun"
name == "Seogun" //true
name == "seogun" //false
name != "seogun" //true
////
var SomeCode = true
SomeCode //true
!SomeCode //false
한 값이 다른 값보다 크거나, 작거나 같은지 여부를 비교하는 네 가지 연산자가 있습니다.
firstScore < secondScore //firstScore가 secondScore보다 작다
firstScore >= secondScore //firstScore가 secondScore보다 크거나 같다
문자열은 자동으로 알파벳 순서를 갖기 때문에 각 문자열에서도 작동합니다.
"Taylor" <= "Swift"
var a = 1.1
var b = 2.2
var c = a + b //3.3
c > 3 //true
c >= 3 //true
c > 4 //false
c < 4 //true
let firstName = "서근"
let secondName = "포뇨"
let firstAge = 40
let secondAge = 10
print(firstName == secondName) //false
print(firstName != secondName) //true
print(firstName < secondName) //true 'ㅅ'이 'ㅍ'보다 작다
print(firstName >= secondName) //false 'ㅍ'이 'ㅅ'보다 크다
print(firstAge == secondAge) //false
print(firstAge != secondAge) //true
print(firstAge < secondAge) //false
print(firstAge >= secondAge) //true
다음과 같이 Enum
을 비교할 수 있도록 Swift에 요청할 수도 있습니다.
enum Sizes: Comparable {
case small
case medium
case large
}
let first = Sizes.small
let second = Sizes.large
print(first < second) //true
참조 비교 연산자
Swift의 유일한 참조 타입인 클래스의 인스터스에서만 참조 연산자를 사용할 수 있습니다. Swift의 기본 데이터 타입은 모두 구조체로 구현되어 있기 때문에 값 타입 이죠. 그렇기 때문에 값의 비교 연산에는 ( ==
) 를 사용하고, 클래스의 인스턴스인 경우에만 ( ===
) 를 사용합니다.
let AValue: Int = 3
let BValue: Int = 5
let CValue: Int = 5
let isSameValueAB: Bool = AValue == BValue // false
let isSameValueBC: Bool = BValue == CValue // true
/* ================ */
let AReference: SomeClass = SomeClass()
let BReference: SomeClass = SomeClass()
let CReference: SomeClass = AReference
let isSameReferenceAB: Bool = AReference === BReference // false
let isSameReferenceAC: Bool = AReference === CReference // true
삼항 조건 연산자
피연산자가 세 개인 삼항 조건 연산자 입니다.
연산자 | 부호 | 설명 |
삼항 조건 연산자 | Question ? A : B | Question(Bool type)이 true이면 A, false이면 B를 반환 |
삼항 조건 연산자를 사용하게 되면 조건식을 간단히 한 줄로 표현할 수 있습니다.
var AValue: Int = 3
var BValue: Int = 5
//A값이 B값보다 작다면 AValue, 그렇지 않다면 BValue 반환
var biggerValue: Int = AValue > BValue ? AValue : BValue // 5
AValue = 0
BValue = -5
biggerValue = AValue > BValue ? AValue : BValue // 0
var AString: String = ""
var BString: String = "String"
var resultString: String = AString.isEmpty ? "비어있음" : "비어있지 않음" // 비어있음
resultString = BString.isEmpty ? "비어있음" : "비어있지 않음" // 비어있지 않음
물론, 조건문 안에 또 다른 삼항 연산자를 넣어줄 수 있고, 여러 번 중첩할 수도 있지만, 중첩을 너무 많이 사용하면 오히려 코드를 이해하기 어렵기 때문에 적절히 사용하는 것이 가장 좋습니다.
범위 연산자
값(수)의 범위를 나타내고자 할 때 사용합니다.
연산자 | 부호 | 설명 |
폐쇄 범위 연산자 | A...B | A부터 B까지의 수를 묶어 범위를 표현. A와 B를 포함 |
반폐쇄 범위 연산자 | A.. <B | A부터 B 미만까지의 수를 묶어 범위를 표현. A를 포함하고 B는 포함하지 않음 |
단반향 범위 연산자 | A... | A 이상의 수를 묶어 범위를 표현. A를 포함 |
...A | A 이하의 수를 묶어 범위를 표현. A를 포함 | |
.. <A | A 미만의 수를 묶어 범위를 표현. A를 포함하지 않음 |
부울 연산자
불리언 값의 논리 연산을 할 때 사용합니다.
연산자 | 표현 | 설멍 |
NOT 부울 연산자 | !B | B의 참, 거짓을 반전 |
AND 부울 연산자 | A && B | A와 B의 불리언 AND 논리 연산을 실행 |
OR 부울 연산자 | A || B | A와 B의 불러언 OR 논리 연산을 실행 |
부울 논리 연산과 비트 논리 연산
부울 논리 연산과 비트 논리 연산을 잘 이해하고 구분하여 사용해야 합니다.
비트 연산자
값의 비트 논리 연산을 위한 연산자입니다.
연산자 | 표현 | 설멍 |
NOT 비트 연산자 | ~A | A의 비트를 반전한 결과를 반환 |
AND 비트 연산자 | A & B | A와 B의 비트 AND 논리 연산자 실행 |
OR 비트 연산자 | A | B | A와 B의 비트 OR 논리 연산을 싱행 |
XOR 비트 연산자 | A ^ B | A와 B의 비트 XOR 논리 연산을 실행 |
비트 이동 연산자(Shift 연산자) | A >> B A << B |
A의 비트를 B만큼 비트를 시프트(이동)함 |
복합 할당 연산자
할당 연산자와 다른 연산자가 하는 일을 한 번에 할 수 있도록 연산자를 결합할 수 있습니다. 이를 복합 할당 연산자라고 합니다.
표현 | 설명 | 같은 표현 |
A += B | A와 B의 합을 A에 할당 | A = A + B |
A -= B | A와 B의 차를 A에 할당 | A = A - B |
A *= B | A와 B의 곱을 A에 할당 | A = A * B |
A /= B | A와 B를 나눈 값을 A에 할당 | A = A / B |
A %= B | A와 B를 나눈 나머지를 A에 할당 | A = A % B |
A <<= N | A를 N만큼 왼쪽 비트 시프트 한 값을 A에 할당 | A = A << N |
A >>= N | A를 N만큼 오른쪽 비트 시프트 한 값을 A에 할당 | A = A >> N |
A &= B | A와 B의 비트 AND 연산 결과를 A에 할당 | A = A & B |
A |= B | A와 B의 비트 OR 연산 결과를 A에 할당 | A = A | B |
A ^= B | A와 B의 비트 XOR 연산 결과를 A에 할당 | A = A ^ B |
오버플로 연산자
연산자 | 부호 | 설멍 |
오버플로 더하기 연산 | &+ | 오버플로에 대비한 뎃셈 연산을 함 |
오버플로 빼기 연산 | &- | 오버플로에 대비한 뺄셈 연산을 함 |
오버플로 곱하기 연산 | &* | 오버플로에 대비한 곱셈 연삼을 함 |
예를 들어서 UInt8
타입은 8비트 정수 타입으로 부호가 없는 양의 정수만 표현하기 때문에 0 아래로 내려가는 계산을 하게 되면 런타임 오류가 발생하게 됩니다. 하지만 오버플로 빼기 연산을 사용하게 되면 오류 없이 오버플로 처리를 해줍니다. 그렇지만 오버플로에 대한 이해 없이 사용하게 된다면 엉뚱한 값을 구할 수도 있습니다.
var unsignedInteger: UInt8 = 0
let errorUnderflowResult: UInt8 = unsignedInteger - 1 // 런타임 오류
let underflowedValue: UInt8 = unsignedInteger &- 1 // 255
unsignedInteger: UInt8.max // 255
let errorOverflowResult: UInt8 = unsignedInteger + 1 // 런타임 오류
let overflowedValue: UInt8 = unsignedInteger &+ 1 // 0
기타 연산자
앞에 소개했던 연산자 외에 Swift 라이브러리에 기본적으로 정의된 연산자를 알아보도록 하겠습니다. 자주 사용하니 꼭 외워두는 것이 좋겠네요.
연산자 | 부호 | 설명 |
nil 병합 연산자 | A ?? B | A가 nil이 아니면 A를 반환하고, A가 nil이면 B를 반환 |
부호변경 연산자 | -A | A의 부호를 변경 |
옵셔널 강제 추출 연산자 | O! | O(옵셔널 개체)의 값을 강제로 추출 |
옵셔널 연산자 | V? | V(옵셔널 값)을 안전하게 추출하거나, V(데이터 타입)가 옵셔널임을 표현 |
nil 병합 연산자
nil
병합 연산자는 옵셔널을 사용할 때 아주 유용한 연산자입니다. 다음 두 코드는 같은 역할을 하지만, 아래의 nil
병합 연산자를 사용하는 것이 훨씬 안전하고 간단한 방법입니다. nil
병합 연산자를 사용하려면 double question marks (??
)를 사용하면 됩니다.
let valueInt: Int = someOptionalInt != nil ? someOptionalInt! : 0
//위 코드와 같은 결과를 볼 수 있지만 훨씬 안전하고 간단하게 사용할 수 있음
let valueInt2: Int = someOptionalInt2 ?? 0
나머지 연산자(Remainder Operator)
위 사칙연산 말고도 추가적으로 나머지 연산자(Remainder Operator)라는 것이 있는데, 나누기를 하고 나머지를 구하는 연산자라고 할 수 있습니다.
"왼손 숫자를 오른손으로 균등하게 나누고 나머지를 돌려준다"
이 연산자 역시 일반 다른 프로그래밍 언어의 나머지 연산자와 동일하게 '%
' 문자를 사용합니다.
나머지 연산자는 a % b
가 있다고 하면 'a
'는 얼마나 많은 수의 'b'가 있는지 알아내고 남은 값(나머지(remainder
))을 반환합니다.
let secondScore = 4
let remainder = 13 % secondScore //1
예를 들어 10 % 3을 계산하기 위해서, 먼저 10에 3이 얼마나 많은지를 계산합니다.
10을 3개씩 나눈 뒤 남은 것이 한 개입니다. 그래서 1을 반환하게 됩니다.
10 % 3 //1
a % b에 대한 답을 구하기 위해 % 연산자는 다음에 오는 공식을 계산하고 출력으로 remainder
를 반환합니다.
a = (b x some multiplier) + remainder
a / b = c
c * b = D
a - D = 반환값
some multipler는 a안에 b가 들어갈 수 있는 최대 개수입니다. 10과 3을 공식에 대입합니다.
10 = (3 x 3) + 1
a의 음수 값에 대한 나머지를 계산할 때에도 같은 방법이 적용됩니다.
-10 % 3 // -1
-10와 3을 공식에 대입합니다. -1이라는 나머지 값을 줍니다.
-10 = (3 x -3) + -1
b의 음수 값에 대해 b의 부호는 무시됩니다. 이는 a % b와 a % -b가 항상 같은 값을 주는 것을 의미합니다.
예시 :
만약 어떠한 행사까지 465일이 남았고 이것이 몇 주 뒤에 시작되는지 Int
를 사용하여 계산하고자 합니다.
let weeks = 465 / 7
print("There are \(weeks) weeks until the event.")
//There are 66 weeks until the event.
위와 같이 코드를 작성하면 행사까지 66주가 남았지만, 이것은 정확한 사실이 아닙니다. 이와 같은 두 정수를 나누면 Swift는 두 정수를 나눈 후, 소수점을 버리기 위해 반올림을 합니다. 465 나누기 7은 정확히 66이 아니므로(66.428...), 이 행사를 놓칠 수도 있습니다.
그렇다면 Double
을 사용하면?
let weeks: Double = 465 / 7
print("There are \(weeks) weeks until the event.")
//There are 66.42857142857143 weeks until the event.
이것 또한 썩 맘에 드는 결과가 아닙니다..
let weeks = 465 / 7
let days = 465 % 7
print("There are \(weeks) weeks and \(days) days until the event.")
//There are 66 weeks and 3 days until the event.
아주 좋은 결과를 받았습니다. 465 % 7 은 3을 반환해줍니다.
465 / 7 = 66.42857 //소수점 뒤는 버려짐
66 * 7 = 462
465 - 462 = 3 //반환값
따라서 465를 7로 나누고 0으로 소수점 뒤를 버리고 66 주를 제공 한 다음, days 나머지 연산자를 사용하여 남은 양을 계산합니다.
Remainder Operator TEST : 문제를 풀려면 이곳을 클릭해주세요.
Double에 Int를 추가할 수 없는 이유는?
Swift에는 문자열(String
), 부울(Bool
) 및 배열(Array
)과 같은 데이터를 저장하는 다양한 방법이 있습니다. 이 숫자 작업에 올 때, Int
, Double
, Float
을 포함하여 몇 가지 특정 유형을 사용합니다.
Swift는 데이터를 다르게 저장하기 때문에 이러한 수치 유형을 가지고 있습니다. 예를 들어, Double
과 Int
는 숫자를 저장하는 데 동일한 양의 메모리를 사용하지만 Int
는 정수만 저장하는 반면 Double
은 소수점 자리 뒤에 값을 저장할 수 있습니다.
따라서, Double
에 Int
에 추가하는 것이 안전하지 않다는 것을 알 수 있습니다. Double
은 Int
가 저장할 수 없는 것을 저장할 수 있습니다.
"글쎄요, Double에 Int를 추가하면 모든 데이터를 저장할 수 있는 새로운 Double을 다시 얻을 수 있지 않나요?"
이 질문의 문제는 Double
이 Int
와 동일한 양의 메모리를 사용하여 값을 저장하지만 데이터를 저장하는 방식이 약간 모호하다는 점입니다. 더 작은 숫자로 엄청 정밀하지만 큰 숫자로 작업을 시작하면 점점 정확도가 높아집니다. 실제로 Double
이 보유할 수 없는 특정 숫자도 있으므로 그 대신 매우 약간 다른 값을 저장합니다.
만약 아래와 같이 코드를 작성하여 빌드한다면 오류가 생깁니다.
//error
let value: Double = 90000000000000001
위 코드를 빌드하면 '900000000000001'은 '더블'로 정확하게 표현되지 않는다고 Swift가 경고합니다.
그리고 이것은 '900000000000000'이 됩니다.
정수(Int
)는 분수 값을 저장할 수 있는 기능이 없지만, 정확한 값을 저장할 수 있는 기능은 가지고 있습니다. 즉, 숫자를 정확하게 저장할 수 있기 때문에 아래 코드는 경고를 생성하지 않습니다.
let value: Int = 90000000000000001
그렇기 때문에 Double
에 Int
에 추가하는 것은 안전하지 않습니다. Double
에 Int
에 추가하면 정확도가 떨어지기 때문입니다.
Swift에서 9000000000000000001만큼 큰 숫자로 작업해야 하는 경우는 거의 없습니다.
그렇지만 문제는 Swift가 코드를 만들 때 사용자의 숫자가 어떻게 되는지 알 수 없다는 것입니다. 따라서 우리는 안전의 문제로 돌아가고 있습니다.
물론 대부분의 경우 안전한 번호로 작업하고 있을 수 있습니다. 하지만 Swift는 예상치 못한 상황이 발생하더라도 위험을 감수하지 않도록 특별히 설계되었습니다.
따라서 Swift는 다양한 숫자 유형 간의 자동 변환을 거부합니다. 즉, Int
에 Double
을 추가할 수 없고 Float
와 Int
를 곱할 수 없습니다.
읽어주셔서 감사합니다🤟
'SWIFT > Grammar' 카테고리의 다른 글
Swift : 기초문법 [클래스 - Class] (0) | 2021.03.01 |
---|---|
Swift : 기초문법 [프로퍼티 #4-1 Static] (0) | 2021.03.01 |
swift : 기초문법 [ 프로퍼티 #1-1 지연 저장 프로퍼티(Lazy)] (0) | 2021.03.01 |
Swift : 기초문법 [Array의 프로퍼티 및 메서드] (3) | 2021.02.28 |
Swift : 기초문법 [String의 프로퍼티 및 메서드] (0) | 2021.02.27 |