🍎swift

[Swift] 연산자 커스텀 타입

Kendrick 2023. 4. 5. 22:34

서론

연산자도 이미 구현되어있는 타입 메서드 입니다.

예를면 String타입이나, Int타입 등이 이미 구현되어있는 메서드 입니다.

//String 타입 
"Hello" + ", Swift!"     // "Hello, Swift!"

//Int 타입 
1 + 2 //3

 

 

BUT.. 열거형, 클레스, 구조체를  + , - , 나 비교( > , =! , == 등등)  등을 사용하고 싶을 때 직접 정의하여 구현이 가능합니다.

연산자 커스텀 타입은 아래와 같은 특성이 있습니다. 

  • extension을 통해 특정 연산자의 논리를 정의 가능
  • 파라미터명은 보통 lhs 와 rhs로 사용

 

enum타입(열거형)

enum타입에서 == 타입 메소드 역시 이미 구현되어 있어 별도의 구현이 필요하지 않지만아래 코드에서 + 연산자 메소드를 원시값 + 원시값을 리턴하게 정의했습니다.

enum Weekday:Int {
    case mon
    case tue
    case wed
    case thu
    case fri
    case sat
    case sun
}



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

Weekday.mon == Weekday.tue //false
Weekday.tue + Weekday.wed //3

 

또한 논리 구조는 개발자 마음대로 커스텀이 가능합니다.

enum Weekday:Int {
    case mon
    case tue
    case wed
    case thu
    case fri
    case sat
    case sun
}

extension Weekday {
    static func + (lhs: Weekday , rhs: Weekday) -> Bool {
        				//리턴타입 수정 
        return (lhs.rawValue + rhs.rawValue) > 2
    }
}

Weekday.tue + Weekday.wed // ture

 

 

1.   사칙연산 및  복합할당 연산자 

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



var vector = Vector2D(x: 3.0, y: 1.0)
let vector1 = Vector2D(x: 2.0, y: 4.0)

//let combinedVector = vector + vector1  //컴파일 에러 연산자가 구현되어있지않음

// + 연산자 구현 
extension Vector2D {
   
    static func + (lhs: Vector2D , rhs: Vector2D) -> Vector2D {
    			  //파라미터로 Vector2D의 값을 받겠음
                  
        return Vector2D(x: lhs.x + rhs.x, y: rhs.y + rhs.y)
        		 //x 값은 첫번째와 두번째 x,y값을 더해서 x,y로 받음
    }

}

let combinedVector = vector + vector1 //Vector2D(x: 5.0, y: 5.0)

 

다른 연산자도 정의 및 사용 가능 

// * 연산자
extension Vector2D {
    static func * (lhs: Vector2D, rhs: Vector2D) -> Vector2D {
        return Vector2D(x: lhs.x * rhs.x, y: lhs.y * rhs.y)
    }
}

// - 연산자
extension Vector2D {
    static func - (lhs: Vector2D, rhs: Vector2D) -> Vector2D {
        return Vector2D(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
    }
}

//복합할당 연산자
extension Vector2D {
    static func += (lhs: inout Vector2D, rhs: Vector2D) {
        lhs = lhs + rhs
    }
}

2.   == (Equatable) ,  > , ... 

  •  ==(Equatable) 구현 시 != 연산자는 자동 구현됨 
  • <  연산자 정의 시 나머지( > , >! 등등) 자동으로 컴파일러가 구현 
  • Equtable타입을 먼저 정의한 뒤 비교 연산자 구현 가능 
struct somePoint {
    var pointA = 0.0
    var pointB = 0.0
}


var pointA = somePoint(pointA: 1.0, pointB: 2.0)
var pointB = somePoint(pointA: 1.0, pointB: 2.5)
var pointC = somePoint(pointA: 1.0, pointB: 2.5)


pointA > pointB
pointC == pointB

위와 같은 코드가 있을 때  컴파일러는 어떤 기준으로 같아야 하는지, 커야하는지 기준을 모르기 때문에 컴파일 에러가 발생.

즉, 개발자는 컴파일러에게 판단 할 수 있는 기준을 만들어주면 됩니다. 

 

 

 

3.   perfix, posfix , infix 정의

전치(perfix) , 후치(postfix) , 중위(infix) 연산자도 개발자 마음대로 정의할 수 있으며 다음과 같은 순서로 정의할 수 있습니다.

  1. 선언: 생략가능
  2. 정의: 선언한 연산자를 구체적으로 정의
  3. 사용: 정의한 연산자를 사용

 

perfix 커스텀

//1. 선언 +++를 perfix연산자로 선안할거야 
prefix operator +++

//2. 정의
extension Int {
    static prefix func+++(num: inout Int) {
        num += 3
    }
}

num = 2

+++num //5

 

postfix 커스텀

var num = 0

num = num + 2

//1. 후치연산자로 ++ 기호를 만들거야~ 라고 선언을 해줌
postfix operator ++

//2. 정의
extension Int {
    static postfix func ++(num: inout Int) {
        num += 1
    }
}

num++ //3

 

infix 커스텀

struct somePoint {
    var pointA = 0.0
    var pointB = 0.0
}


var pointA = somePoint(pointA: 1.0, pointB: 2.0)
var pointB = somePoint(pointA: 1.0, pointB: 2.0)

infix operator +-

extension somePoint {
    static func +- (lhs: somePoint, rhs: somePoint) -> somePoint {
        return somePoint(pointA: lhs.pointA + rhs.pointA, pointB: rhs.pointB - rhs.pointB)
    }
}

var pointD = pointA +- pointB
print(pointD) //somePoint(pointA: 2.0, pointB: 0.0)