티스토리 뷰

반응형

Swift Docs > Advanced Operators > Operator Methods, Custom Operators 내용을 기반으로 하고 있습니다.


[1] Operator Methods 

Class와 Structure은 existing operators 에 대해 그들 자신의 구현을 제공할 수 있습니다.  

이것은 'existing operators 를 overloading 한다' 라고 말할 수 있습니다. 

existing operators 목록은 Operator Declarations 문서에서 볼 수 있습니다.

 

하지만 모든 operator을 overload 할 수 있는 것은 아닙니다. 

1️⃣ default assignment operator (=)

2️⃣ ternary conditional operator (a ? b : c) 

는 오버로드 될 수 없습니다. 

 

#  Infix Operator

아래 예제는 + operator method 를 custom structure에 정의한 예제 입니다.

struct Vector2D {
    var x = 0.0, y = 0.0
}

extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
}

 

1.

operator 메소드는 type 메소드로 정의되었고 메소드는 이름은 overload될 + operator와 동일한 이름임을 확인할 수 있습니다. 

 

2.

덧셈은 벡터에 대한 필수적인 동작이 아니기 때문에 Vertor2D의 main structure declaration이 아닌 extension에 정의하였습니다. 

 

3.

+ operator는 두개의 타겟에 대한 연산을 수행하는 binary operator이고 두개의 target 사이에 위치하는 infix operator입니다.  그래서 두개의 input parameter를 받고 있고 + operator 왼쪽에 위치하는 것을 left, 오른쪽에 위치하는 것을 right라고 나타내기 위해  파라미터 네임을 left, right라고 해줬습니다. 

 

 

정의한 + operator는 아래와 같이 사용될 수 있습니다.

let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)

 

 

# Unary Operator

unary operator는 single target에 대해 연산을 하는 operator를 말합니다. 

-a 처럼 target 앞에 operator가 위치하면 prefix unary operator라고 하고

b! 처럼 target 뒤에 operator가 위치하면 postfix unary operator라고 합니다. 

 

operator method를 정의할 때, func keyword앞에 prefix 또는 postfix modifier를 붙여서 

prefix 또는 postfix unary operator를 구현하면 됩니다. 

 

아래 예제는 unary minus operator method를 구현한 예제입니다.

extension Vector2D {
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
}

 

이렇게 구현하면 아래와 같이 사용될 수 있습니다.

let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative is a Vector2D instance with values of (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive is a Vector2D instance with values of (3.0, 4.0)

 

# Compound Assignment Operators

Compound assignment operators는 assignment (=) 를 다른 operation과 결합한 것을 말합니다. 

예를들어 += operator (addition assignment operator) 가 있습니다. += operator는 addition과 assignment를 single operation으로 combine한 operator 입니다. 

 

compound assignment operator를 구현할 때, left input parameter type 을 inout으로 해줍니다.

왜냐하면 해당 parameter의 value는 operator method안에서 즉시 수정될 것이기 때문입니다. 

 

아래 예제는 addition assignment operator method를 구현한 예제입니다. 

위에서 정의했던 addition operator 를 사용해주고 있습니다. 

extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left = left + right
    }
}

 

그럼 아래와 같이 사용될 수 있겠습니다. 

var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original now has values of (4.0, 6.0)

 

# Equivalence Operators

== operator (equal to operator) 와 != operator (not equal to operator) 가 equivalence operators 에 속합니다. 

기본적으로 custom class와 structure에 equivalence operators 을 따로 구현해줄 필요가 없습니다.

Equatable protocol 을 채택하면 Swift가 알아서 구현을 해주기 때문입니다. 

다만 아래 조건을 만족했을 경우에만 해당됩니다. 

 

https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID627

 

 

Vector2D는 위 조건을 만족하기 때문에 따로 구현을 안해줘도 되지만 학습 상 구현해보겠습니다! 

infix operator를 구현해줬을 때와 동일하게 구현해주면 되겠습니다. 

extension Vector2D: Equatable {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
        return (left.x == right.x) && (left.y == right.y)
    }
}

 

아래처럼 사용될 수 있습니다.

let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    print("These two vectors are equivalent.")
}
// Prints "These two vectors are equivalent."

 

 

[2] Custom Operators 

Swift에서 제공하는  standard operators 를 오버로딩하는 것 말고 your own custom operator 도 정의할 수 있습니다. 

operator에 사용될 수 있는 character 목록은 Operators 를 봐주시면 됩니다. 

 

# Prefix Operator

+++ operator (prefix doubling operator) 라는 custom operator를 만들어보겠습니다. 

 

우선 새로운 operator를 operator keyword를 사용해서 global level에 선언해줘야합니다.

이때 prefix, infix or postfix modifier 도 같이 마킹해줍니다. 

그리고 원하는  operator name을 작성해줍니다. 

 

그 다음  +++ operator 를 구현해주면 됩니다. 

prefix operator +++
extension Vector2D {
    static prefix func +++ (vector: inout Vector2D) -> Vector2D {
        vector += vector
        return vector
    }
}
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)

 

# Infix Operator

또 다른 예제로  +- operator를 정의해보겠습니다.  

infix operator +-
extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector is a Vector2D instance with values of (4.0, -2.0)

 

infix operator의 경우, 여러 infix operator들과 함께 있을 때의 우선순위를 고려해줘야합니다 (참고: Precedence and Associativity)

 

우선 순위 그룹(precedence group)을 명시적으로 배치하지 않은 custom infix operator의 경우, 

DefaultPrecedence 그룹에 배치 됩니다.

(DefaultPrecedence는 TernaryPrecedence 보다 바로 높은 우선 순위를 가진 그룹입니다) 

https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations

 

 

우선순위 그룹에 명시적으로 배치해주고 싶다면 아래의 형태로 선언해주면 됩니다. 

 

우리가 정의한 +- operator를 AdditionPrecedence precedence group에 속하도록 해주고 싶다고 해보겠습니다. 

 

이렇게 해주면 됩니다! 

infix operator +-: AdditionPrecedence
extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}

 

더 구체적으로 우선순위를 지정해주고 싶다면, 

Precedence Group 을 따로 선언하고 이 그룹에 속하도록 해주면 됩니다.  (참고:  Precedence Group Declaration )

 

 

 

 

반응형
댓글