Swift/Swift 기본문법

Swift 기본 문법 - 6. 연산자

728x90

연산자

연산자는 다른언어와 비슷한 부분이 많아 몰랐던 부분만 작성하였습니다.

 

5.1.5 범위 연산자

값(수)의 범위를 나타내고자 할 때 사용합니다.

폐쇄 범위 연산자 : A...B : A부터 B까지의 수를 묶어 범위를 표현합니다.

반폐쇄 범위 연산자 : A.. < B : A부터 B 미만까지의 수를 묶어 범위를 표현합니다. A를 포함하고 B는 포함하지 않습니다.

단방향 범위 연산자 :

A... : A 이상의 수를 묶어 범위를 표현합니다.

...A : A 이하의 수를 묶어 범위를 표현합니다.

.. < A : A 미만의 수를 묶어 범위를 표현합니다.

 

텍스트로 봐서는 범위연산자가 어떤 값들의 범위를 나타내는것 같은데 어떻게 사용되는지 모르겠다.

뒤에 반복문에서 코드를 통해 더 자세히 살펴보자.

 

5.1.9 오버플로연산자 

프로그래밍에서 정수 타입의 최댓값과 최솟값이 존재하고 이를 넘거나 더 낮게 내려가면 오버플로우가 발생한다.

스위프트에서는 오버플로우가 발생 할 때 에러가 아닌 0 또는 최댓값으로 다시 돌아가는 연산자가 존재한다.

코드를 통해 살펴보자

 

var unsignedInteger: UInt8 = 0
//let errorUnderflowResult: UInt8 = unsignedInteger - 1
let underflowedValue: UInt8 = unsignedInteger &- 1  // 255

unsignedInteger = UInt8.max
//let errorOverflowResult: UInt8 = unsignedInteger + 1
let overflowedValue: UInt8 = unsignedInteger &+ 1  // 0

5.1.10 기타 연산자

자바스크립트 언어는 없는 옵셔널과 nil에 관한 연산자가 존재한다.

 

nil 병합 연산자 : A ?? B (A가 nil이 아니면 A를 반환하고, A가 nil이면 B를 반환합니다.)

부호변경 연산자 : -A (A(수)의 부호를 변경합니다.)

옵셔널 강제 추출 연산자 : O! (O(옵셔널 개체)의 값을 강제로 추출합니다.) // 지양하는게 좋다.

옵셔널 연산자 : V? (V(옵셔널 값)을 안전하게 추출하거나, V(데이터 타입)가 옵셔널임을 표현합니다.)

 

nil 병합 연산자는 옵셔널을 사용할 때 유용한 방법입니다.

위 코드에서도 사용을 했었고, 아래코드처럼 nil일 때, nil이 아닐 때 값을 설정 할 수 있습니다.

let valueInt: Int = someOptionalInt != nil ? someOptionalInt! : 0

// 위 코드와 동일한 결과
let valueInt: Int = someOptionalInt ?? 0

 

5.3 사용자 정의 연산자

 *, +, -, <, / 등등 다양한 연산자를 언어에서 사용 할 수 있습니다.

스위프트에서 개발자가 직접 연산자를 만들어 사용 할 수 있습니다.

사용자 정의 연산자는 아스키 문자 /, =, -, +, !, *, %, <. >, &, |, ^, ?, ~ 를 결합해서 사용합니다.

 

5.3.1 전위 연산자 정의와 구현 

Int 타입의 제곱을 구하는 연산자로 **을 전위연산자로 사용하려고 할때, 아래와 같이 구현합니다.

prefix operator **

// Int형 타입의 제곱을 구현하겠다.
prefix func ** (value: Int) -> Int {
	return value * value
}

let minusFive: Int = -5
let sqrtMinusFive: Int = **minusFive

print(sqrtMinusFive)

String 형으로도 구현을 할 수 있습니다.

prefix operator **

perfix func ** (value: String) -> String {
	return value + " " + value
}

let reulstString: String = **"kemi"

print(resultString)  // kemi kemi

전위, 후위 연산자도 비슷한 방법으로 생성이 가능합니다.

 

 == 연산자도 동작을 바꿔줄 수 있습니다.

class Car {
    var modelYear: Int?      // 연식
    var modelName: String?   // 모델 이름
}

struct SmartPhone {
    var company: String?     // 제조사
    var model: String?       // 모델
}

// Car 클랫의 인스턴스끼리 == 연산 했을 때 동작하는 함수
func == (lhs: Car, rhs: Car) -> Bool {
    return lhs.modelName == rhs.modelName
}

// SmartPhone 구조체의 인스턴스끼리 == 연산했을 때 동작하는 함수
func == (lhs: SmartPhone, rhs: SmartPhone) -> Bool {
    return lhs.model == rhs.model
}

let myCar = Car()
myCar.modelName = "S"

let yourCar = Car()
yourCar.modelName = "S"

var myPhone = SmartPhone()
myPhone.model = "SE"

var yourPhone = SmartPhone()
yourPhone.model = "6"

print(myCar == yourCar)
print(myPhone == yourPhone)

 

지금것 연산자 함수를 전역함수로 구현을 했습니다.

특정 타입에 군한된 연산자함수라면 그 타입 내부에 구현되는 것이 읽고 이해하는게 쉽습니다.

아래 코드와 같이 class 내에서 연산자 함수를 구현 할 수 있습니다.

class Car {
    var modelYear: Int?      // 연식
    var modelName: String?   // 모델 이름
    
    // Car 클랫의 인스턴스끼리 == 연산 했을 때 동작하는 함수
    static func == (lhs: Car, rhs: Car) -> Bool {
        return lhs.modelName == rhs.modelName
    }
    
}

struct SmartPhone {
    var company: String?     // 제조사
    var model: String?       // 모델
    
    // SmartPhone 구조체의 인스턴스끼리 == 연산했을 때 동작하는 함수
    static func == (lhs: SmartPhone, rhs: SmartPhone) -> Bool {
        return lhs.model == rhs.model
    }
}



let myCar = Car()
myCar.modelName = "S"

let yourCar = Car()
yourCar.modelName = "S"

var myPhone = SmartPhone()
myPhone.model = "SE"

var yourPhone = SmartPhone()
yourPhone.model = "6"

print(myCar == yourCar)
print(myPhone == yourPhone)

 

사용자 정의 연산자는 복잡한 연산을 하나의 특수문자로 구현하기 때문에 코드가 깔끔해 질 수 있습니다.

 

하지만 저는 이런 연산자 사용하는 건 지양할 것 같습니다. 

기존 스위프트에서 제공한다고 착각 할 수 도 있고, 사용자 정의 연산자를 선언 한 것을 인지하지 못한다면 유지보수 할 때도 힘들어보이기 때문에 사용하진 않을 것 같습니다.

 

반응형