[SWIFT] 연산자 오버로딩 + 연산자 커스텀

2020. 11. 28. 02:45SWIFT

반응형

여러분 코딩을 하다 보면 연산자를 다들 많이 사용하셨죠.

?, +, -, *, /, %, && 같은 연산자들이 모두 Swift에서 기본으로 지원하는 연산자들이에요.

 

그렇다면 이 연산자들 직접 커스텀해서 사용할 수 있는거 아셨나요?

오늘은 이 연산자를 직접 커스텀해서 사용해볼게요.

 

우선 연산자를 사용하기 위해 3가지 방법이 있다.

  • infix : 연산자가 피연산자의 중앙에 위치 ex) 1 * 1, 1 + 1, 1 - 1
  • prefix : 연산자가 피연산자의 앞에 추가된다 ex) -1, +1
  • postfix : 연산자가 피연산자의 뒤에 추가되는 것을 말한다 ex) Optional(1)!

 

우선 기본에 Swift가 지원하지 않은 연산자를 구현하는 방법을 먼저 보겠습니다!!

 

위에서 연산자를 사용하기 위한 3가지 방법이 있다고 설명한 이유가 있습니다.

바로 연산자를 정의하기 전에 연산자와 피연산자의 관계를 정의해야하기 때문이에요.

 

그렇다면 바로 커스텀한 연산자를 만들어볼게요.

prefix operator **		// 전위 연산자
infix operator **		// 중위 연산자
postfix operator **		// 후위 연산자

이렇게 3가지 방식으로 연산자를 전역으로 선언할 수 있어요.

 

여기서 주의해야할 점은 infix의 경우에는 현재처럼 선언해도 사용은 가능하지만 만약 연산에서 연속으로 연산자를 사용할 경우 우선순위를 정해주지 않아서 컴파일 에러가 날 수 있어요.

 

그렇기 때문에, 다음과 같이 연산자의 우선순위를 지정해주어야해요.

infix operator ***: MultiplicationPrecedence
infix operator ***: AdditionPrecedence

여기서 여러가지 우선순위가 있는데 Apple 개발자 홈페이지를 참조하면 될 것 같아요.

 

그럼 이제 연산자를 커스텀해서 사용하는 코드를 보면서 알아볼게요.

 


 

  • Custom Prefix Operator
prefix operator ***

prefix func ***(number: Int) -> Int {
    return pow(number, 2)
}

prefix func ***(number: inout Int) {
    number = pow(number, 2)
}

extension Int {
    static func ***(number: Int) -> Int {
        return pow(number, 2)
    }
}

 

  • Custom Infix Operator
infix operator ***: AdditionalPrecedence

func ***(lhs: Int, rhs: Int) -> Int {
    return lhs + rhs
}

extension Int {
    static func ***(lhs: Int, rhs: Int) -> Int {
        return lhs + rhs
    }
}

 

  • Custom Postfix Operator
postfix operator ***

postfix func ***(number: Int) -> Int {
    return -number
}

postfix func ***(number: inout Int) {
    number = -number
}

extension Int {
    static func ***(number: Int) -> Int {
        return -number
    }
}

 

 

이렇게 만들어서 사용할 수 있어요.

 

여기서 조금 더 프로토콜로 활용하고 싶으면

protocol Additionable {
    static func ****(lhs: Self, rhs: Self) -> Self
}

extension Int: Additionable {
    static func ****(lhs: Int, rhs: Int) -> Int {
        return lhs + rhs
    }
}

이런 방법도 있을 것 같아요!!

 

마지막으로 Equatable을 활용해서 각 타입에 비교 연산자 역시 커스텀해서 사용할 수 있어요.

 

예를 들어, Point라는 객체가 있어요. 

이 객체를 두 개 비교하고 싶은데 그냥 ==을 사용해서 비교하면 컴파일 에러가 뜬다는거... 그렇다면 어떻게 할 수 있을까요.

 

바로 Equatable을 사용하는 것이에요.

struct Point {
    var x: Int
    var y: Int
}

extension Point: Equatable {
    func ==(lhs: Point, rhs: Point) -> Bool {
        return (lhs.x == rhs.x && lhs.y == rhs.y)
    }
}

Point(x: 1, y: 1) == Point(x: 1, y: 1)		// true
Point(x: 1, y: 2) == Point(x: 1, y: 3)		// false

 

이렇게도 사용할 수 있어요.

 

이상으로 오늘은 커스텀 연산자를 사용하는 방법에 대해 알아봤어요.

반응형