연산자 오버로딩 - Operator Overloading
이미 존재하는 연산자가 새로운 피연산자를 처리할 수 있도록 확장한다.
struct Point {
var x = 0.0
var y = 0.0
}
let p1 = Point(x: 12, y: 34)
let p2 = Point(x: 67, y: 89)
p1 == p2 // error : Binary operator '==' cannot be applied to two 'Point' operands
==
연산자는 Int, Double, String 등의 다양한 데이터 타입의 동등성을 비교해주는 연산자이다. 하지만 내가 방금 작성한 구조체 Point에 대해서는 ==
연산자를 통한 동등성 비교가 가능하지 않다.
따라서 같은 형식의 데이터 간의 연산을 처리하기 위해서는 이미 존재하는 연산자 메소드를 오버로딩해줄 필요가 있다.
그 전에, 연산자 메소드를 구현할 때 주의해야 할 점은 다음과 같다:
- 연산자가 가지고 있는 우선순위와 결합법칙을 바꾸지 않는다.
- 가능한 원래 기능과 동일하거나 유사한 기능을 하도록 구현해야 한다.
- 이미 존재하는 연산자의
파라미터
와Return type
을 일치시켜야 한다.
struct Point {
var x = 0.0
var y = 0.0
}
extension Point: Equatable {
static func ==(lhs: Point, rhs: Point) -> Bool {
return (lhs.x == rhs.x) && (lhs.y == rhs.y)
}
}
let p1 = Point(x: 12, y: 34)
let p2 = Point(x: 67, y: 89)
p1 == p2 // false
p1 != p2 // true
a == b
는a != b
가 false임을 암시한다.그러므로, 따로
!=
에 대한 오버로딩을 해줄 필요가 없다.
어떤 데이터의 값의 동등성을 판단하기 위해서는 해당 데이터의 타입이 Equatable
프로토콜을 채택하고 있어야 한다. 참고 - Equatable에 대한 애플 개발자 문서
따라서 Point
라는 구조체가 Equatable
프로토콜을 채택하도록 함으로써 동등성을 판단할 수 있게 해준 후, 두 Point
구조체의 x, y 값이 같은지 비교하는 ==
함수를 오버로딩한 코드다.
단항 연산자 오버로딩 - Unary Operator Overloading
-
전위 연산자 - Prefix Operator
피연산자 앞에 붙는 연산자이다.
메소드를 선언할 때
prefix
키워드를 붙여 선언하면 된다.extension Point { static prefix func -(pt: Point) -> Point { return Point(x: -pt.x, y: -pt.y) } } let pt1 = Point(x: 1.0, y: 2.0) let pt2 = -pt1 pt2.x // -1.0 pt2.y // -2.0
-
후위 연산자 - Postfix Operator
피연산자 뒤에 붙는 연산자이다.
메소드를 선언할 때
postfix
키워드를 붙여 선언하면 된다.extension Point { static postfix func ++(pt: inout Point) -> Point { let ret = pt pt.x += 1 pt.y += 1 return ret } } var pt1 = Point(x: 1.0, y: 2.0) var pt2 = pt1++ pt2.x // 1.0 pt2.y // 2.0 pt1.x // 2.0 pt1.y // 3.0
inout : 함수가 호출됐을 때, 값으로 전달받은 인자가 파라미터에 복사되고, 함수가 반환(return)될 때 함수 내에서 변경된 값이 다시 본래의 값에 할당된다 (
Call by reference
가 아닌Copy-in Copy-out
).
사용자 정의 연산자 - Custom Operators
Swift가 지원하지 않는 연산자를 직접 구현하는 방법을 알아보자.
연산자의 이름을 정의하기 전에, 연산자와 피연산자의 위치 관계를 명시해줘야 한다.
prefix operator *** // 전위 연산자, 피연산자 앞에 연산자가 오는 경우
postfix operator *** // 후위 연산자, 피연산자 뒤에 연산자가 오는 경우
infix operator *** // 피연산자들 사이에 연산자가 오는 경우
사용자 정의 연산자명으로 사용할 수 없는 기호는 다음과 같다:
(
,)
,[
,]
,.
,,
,:
,;
,=
,@
,#
,&(prefix operator)
,->
,?
,!(postfix operator)
,&grave
사용자 정의 연산자는 사용하기 전에 C언어의 함수 프로토타입 선언처럼 Global scope에 따로 선언이 필요한 것 같다.
-
Custom Prefix Operator
prefix operator +++ extension Int { static prefix func +++(num: inout Int) { num += 2 } }
-
Custom Postfix Operator
postfix operator --- extension Int { static postfix func ---(num: inout Int) { let tmp = num num -= 2 return tmp } }
-
Custom Infix Operator
Custom Infix Operator는 우선순위 정의가 필요하다. 따로 정의를 하지 않을 경우
DefaultPrecedence
그룹에 포함되며, 식 안에서 혼자 사용될 경우 문제가 없지만 다른 연산자들과 함께 사용될 경우에는 에러가 발생한다. 아래 표를 참고하여 우선순위를 설정해 주자.Operators Precedence Groups +, - AdditionPrecedence
*, / MultiplicationPrecedence
<, <=, >, >=, ==, != ComparisonPrecedence
=, += -=, *=, /= AssignmentPrecedence
infix operator *+* : MultiplicationPrecedence
extension Int {
static func *+*(left: Int, right: Int) -> Int {
return (left * right) + (left * right)
}
}
-
새로운 우선순위 그룹 생성하기
precedencegroup Name { higherThan: // LowerGroupName lowerThan: // HigherGroupName associativity: // associativity(left, right, none) }
-
higherThan
: 새로운 우선순위 그룹보다 낮은 우선순위의 그룹명을 입력해 준다. -
lowerThan
: 새로운 우선순위 그룹보다 높은 우선순위의 그룹명을 입력해 준다. -
associativity
: 해당 우선순위 그룹의 결합 규칙에 대해 정의한다.left
,right
,none
중에 하나를 지정하면 되며, 아무것도 입력하지 않을 경우none
로 지정된다.
세 필드는 모두 생략 가능하지만,
higherThan
과lowerThan
중에 하나는 꼭 입력해야 한다.precedencegroup MyPrecedence { higherThan: AdditionPrecedence associativity: left } infix operator *+* : MyPrecedence extension Int { static func *+*(left: Int, right: Int) -> Int { return (left * right) + (left * right) } } 1 *+* 2 + 3 // 7
-
'Development > Swift' 카테고리의 다른 글
[Swift]Swift가 제공하는 연산자들 - Operators in Swift (2) (0) | 2020.07.15 |
---|---|
[Swift]Swift가 제공하는 연산자들 - Operators in Swift (1) (0) | 2020.07.15 |
[Swift]이름 정의 규칙 - Camel Case (0) | 2020.03.03 |