morijwana
수로그
morijwana
전체 방문자
오늘
어제
  • 분류 전체보기
    • 강의노트
    • Machine Learning
      • Pandas
      • NLP
    • Computer Science
      • Linux
      • TIL
    • Development
      • React
      • Swift
      • Javascript
    • 스터디 기록
      • Clean Code
      • 구글 BERT의 정석
      • 개발도서
      • 기타
    • Problem Solving
      • Baekjoon
      • ICPC Sinchon
    • 끄적
      • 끄적끄적
      • 요리왕

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 구부정스터디
  • 프로그래밍언어론
  • 프레임워크없는프론트엔드개발
  • 백준
  • Bert
  • GDSC Sookmyung
  • word2vec
  • cs224n
  • ML
  • 자연어처리
  • Pandas
  • 구글BERT의정석
  • nlp
  • 민트하임스터디
  • Solution Challenge
  • 데이터사이언스
  • 회고
  • gdsc
  • 개발도서
  • Python

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
morijwana

수로그

Development/Swift

[Swift]연산자 메소드 - Operator Method

2020. 7. 15. 14:31

연산자 오버로딩 - 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에 대해서는 == 연산자를 통한 동등성 비교가 가능하지 않다.

따라서 같은 형식의 데이터 간의 연산을 처리하기 위해서는 이미 존재하는 연산자 메소드를 오버로딩해줄 필요가 있다.

그 전에, 연산자 메소드를 구현할 때 주의해야 할 점은 다음과 같다:

  1. 연산자가 가지고 있는 우선순위와 결합법칙을 바꾸지 않는다.
  2. 가능한 원래 기능과 동일하거나 유사한 기능을 하도록 구현해야 한다.
  3. 이미 존재하는 연산자의 파라미터와 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
    'Development/Swift' 카테고리의 다른 글
    • [Swift]Swift가 제공하는 연산자들 - Operators in Swift (2)
    • [Swift]Swift가 제공하는 연산자들 - Operators in Swift (1)
    • [Swift]이름 정의 규칙 - Camel Case
    morijwana
    morijwana
    행복한 휴학생의 devlog

    티스토리툴바