티스토리 뷰

반응형

이번 글에서는 Swift 공식 문서의 27번째 단원인 Advanced Operators를 읽고 정리한 글을 쓰려고 합니다.

 

Swift 공식문서 27단원 - Advanced Operators

Advanced Operators

공식문서의 2단원인 Basic Operators에서 설명된 연산자 외에도 Swift에는 더 복잡한 값의 조작을 수행하는 여러 고급 연산자를 제공한다. 여기에는 C, Objective-C에서 익숙한 모든 비트 및 비트 이동 연산자가 포함된다.

 

C의 산술 연산자와 달리 Swift의 산술 연산자는 기본적으로 오버플로 되지 않는다. 오버플로 동작은 트랩 되고 오류로 보고된다. 오버플로 동작을 선택하려면 오버플로 더하기 연산자 (& +)와 같이 기본적으로 오버플로 되는 Swift의 두 번째 산술 연산자 집합을 사용한다. 이러한 모든 오버플로 연산자는 &로 시작한다.

 

구조체, 클래스, 열거형을 정의할 때 표준 Swift 연산자를 커스텀화하는 것이 유용할 수 있다. Swift를 사용하면 이러한 연산자의 맞춤형 구현을 쉽게 제공하고 생성하는 각 타입에 대한 동작이 정확히 무엇인지 결정할 수 있다.

 

이미 정의된 연산자로 제한되지 않으며 Swift는 사용자 지정 우선 순위 및 연관성 값을 사용하여 infix, prefix, postfix, assignment 연산자를 자유롭게 정의할 수 있다. 이러한 연산자는 미리 정의된 연산자와 같이 코드에서 사용 및 채택될 수 있고 새로 정의한 연산자를 지원하도록 기본 타입을 익스텐션 할 수도 있다.


Bitwise Operators

비트 연산자를 사용하면 데이터 구조 내에서 개별 raw 데이터 비트를 조작할 수 있다. 그래픽 프로그래밍 및 장치 드라이버 생성과 같은 저 수준의 프로그래밍에 자주 사용된다. 비트 연산자는 사용자 지정 프로토콜을 통한 통신을 위한 데이터 인코딩 및 디코딩과 같은 외부 소스의 raw 데이터로 작업할 때도 유용할 수 있다.

 

Swift는 C에서 사용가능한 모든 비트 연산자를 지원한다. 이런 비트 연산자를 하나씩 알아보자.

Bitwise NOT Operator

비트 NOT 연산자 (~)는 숫자의 모든 비트를 반전한다.

비트 NOT 연산자는 접두사 연산자이며 공백 없이 적용하려는 값 바로 앞에 쓰면 된다.

let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits  // equals 11110000

위의 코드와 같이 NOT 연산자를 사용할 수 있다. UInt8 정수형은 8비트를 가지며 0에서 255 사이의 모든 값을 저장할 수 있다. 위의 예제에서는 처음 4 비트가 0으로 설정되고 두 번째 4비트가 1로 설정된 00001111로 UInt8 정수를 초기화한다. 이는 10진수로는 15이다.

 

그런 뒤 그 값에 비트 NOT 연산자를 사용한 값을 할당한 inverteBits 상수를 만든다. 이렇게 만들어진 inverteBits 상수는 아까 만든 값에서와 모든 비트가 반전된다. 0은 1이 되고 1은 0이된다. 즉 11110000이 되며 이는 10진수 값 240과 같아진다.

Bitwise AND Operator

비트 AND 연산자 (&)는 두 숫자의 비트를 결합한다. 두 입력 숫자에서 비트가 1인 경우에만 비트가 1로 설정된 새로운 숫자를 반환한다.

let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8  = 0b00111111
let middleFourBits = firstSixBits & lastSixBits  // equals 00111100

위의 코드와 같이 2개의 수를 가지고 AND 연산자를 적용하면 같은 자리에 둘 다 1일 경우에만 1을 갖는 새로운 숫자를 반환한다. 따라서 위의 코드에서 새로 만들어지는 숫자는 00111100이며 이는 10진수로는 60이다.

Bitwise OR Operator

비트 OR 연산자 (|)는 두 숫자의 비트를 비교한다. 두 숫자의 어떤 자리에 하나라도 비트가 1이면 비트가 1로 설정된 숫자를 반환한다.

let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits  // equals 11111110

위의 코드와 같이 2개의 숫자를 가지고 OR 연산자를 적용하면 같은 자리에 하나라도 1일 경우에 1을 갖는 새로운 숫자를 반환한다. 따라서 위의 코드에서 새로 만들어지는 숫자는 11111110이며 이는 10진수 254와 같다.

Bitwise XOR Operator

비트 XOR 연산자또는 exclusive OR 연산자 (^)는 두 숫자의 비트를 비교한다. 두 숫자의 어느 자리 비트가 다른 경우에는 1을, 같을 경우에는 0을 설정한 숫자를 반환한다.

let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits  // equals 00010001

위의 예에서 어떤 자리에서 값이 다르면 1로 설정된 비트를 갖게 된다. 따라서 위의 예에서 비트 XOR의 연산의 결과로 나오는 값을 00010001이며 이는 10진수 17과 같다.

Bitwise Left and Right Shift Operators

비트 왼쪽 시프트 (<<), 오른쪽 시프트(>>) 연산자는 아래에서 정의된 규칙에 따라 숫자의 모든 비트를 특정 자리 수 만큼 왼쪽 또는 오른쪽으로 이동한다.

 

이렇게 비트를 이통시키면 2배로 곱하거나 나누는 효과가 있다. 만약 정수의 비트를 왼쪽으로 이동시키면 값이 2배가 되며 오른쪽으로 이동하면 값이 절반으로 줄어든다. 

Shifting Behavior for Unsigned Integers

부호가 없는 정수에 대한 비트 이동 동작은 다음과 같은 단계를 거친다.

  1. 기존 비트는 요청된 자리 수만큼 왼쪽 또는 오른쪽으로 이동한다.

  2. 정수 저장소의 경계를 넘어 이동된 모든 비트는 삭제된다.

  3. 원래 비트가 왼쪽 또는 오른쪽으로 이동 한 뒤에 남겨진 공백에는 0이 삽입된다.

이러한 접근 방식을 논리적 이동 (logical shift)라고 한다.

위의 그림에서 왼쪽은 11111111 << 1을 한 결과이고 오른쪽은 11111111 >> 1을 한 결과이다. 위의 그림에서 처럼 파란색 숫자는 방향에 따라 이동하고 회색 숫자는 삭제되며 남은 칸에는 0이 삽입된다.

let shiftBits: UInt8 = 4   // 00000100 in binary
shiftBits << 1             // 00001000
shiftBits << 2             // 00010000
shiftBits << 5             // 10000000
shiftBits << 6             // 00000000
shiftBits >> 2             // 00000001

Swift에서는 위와 같이 부호 없는 정수에서 비트 이동 연산을 할 수 있다. 

비트 이동을 사용하여 다른 데이터 타입 내의 값을 인코딩하고 디코딩 할 수 있다. 다음 예를 보며 이해해보자.

let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16    // redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF           // blueComponent is 0x99, or 153

위의 코드는 pink라는 UInt32 상수를 사용하여 분홍색에 대한 Cascading Style Sheets 색상값을 저장한다. CSS 색상값 #CC6699는 Swift의 16진수 표현에서 0xCC6699로 작성된다. 이 색상은 비트 AND, >> 연산자에 의해 빨강(CC), 초록(66), 파랑(99) 구성요소로 분해된다.

 

빨간색 구성 요소는 숫자 0xCC6699, 0xFF0000 사이에 비트 AND 연산을 수행하여 얻는다. 0xFF0000의 0은 0xCC6699의 두 번째 및 세 번째 바이트를 효과적으로 masking 하여 6699를 무시하고 결과로 0xCC0000을 남긴다.

 

그런 뒤 이 숫자는 오른쪽으로 16칸 이동하게 된다. (>> 16) 16진수의 각 문자 쌍은 8 비트를 사용하므로 오른쪽으로 16자리를 이동하면 0xCC0000이 0x0000CC로 변환된다. 이는 10진수 값이 204인 0xCC와 동일하다.

 

마찬가지로 녹색 구성요소는 숫자 0xCC6699, 0x00FF00 사이에 비트 AND 연산을 수행하여 얻어지고 출력 값은 0x006600이다. 이를 >> 8 연산을 사용하여 0x66 값을 제공한다.

 

파란색 구성요소는 0xCC6699, 0x0000FF 사이에 비트 AND를 수행하여 얻으며 출력 값은 0x000099가 된다. 이는 이미 0x99와 같으므로 비트 이동 연산은 하지 않아도 된다.

Shifting Behavior for Signed Integers

부호가 있는 정수는 이진수로 표현되는 방식 때문에 부호가 없는 정수보다 이동 연산이 더 복잡해진다. 

 

부호가 있는 정수는 첫 번째 비트(부호 비트라고 한다)를 사용하여 정수가 음수인지 양수인지 나타낸다. 이 비트 값이 0이면 양수를 의미하고 1이면 음수를 의미한다.

 

나머지 비트(값 비트라고 한다.)는 실제 값을 저장한다. 양수의 경우엔 부호가 없는 정수와 마찬가지로 0부터 위쪽으로 세어서 저장된다. 

위의 예는 Int8 내부의 비트로 4라는 숫자를 찾는 방법이다. 첫 번째 비트, 즉 부호 비트가 0이기 때문에 이는 양수를 나타내는 비트이다. 그 뒤의 7개의 값 비트는 이진 표기법으로 작성된 숫자 4이다.

 

하지만 음수의 경우에는 다르게 저장된다. 절대 값을 2에서 n의 거듭 제곱으로 빼서 저장한다. 여기서 n은 값 비트의 수이다. 8 비트 숫자에는 7 개의 값 비트가 있기 때문에 2의 7 제곱 또는 128을 의미한다. 그럼 음수 비트를 보며 어떻게 다른지 직접 보자.

이번에는 첫 번째 비트 즉 부호 비트가 1이기 때문에 이는 음수를 나타내는 비트임을 알 수 있다.

 값 비트는 124를 갖는 이진값인 것을 볼 수 있다.

 

음수에 대한 인코딩을 2의 보수 표현이라고 한다. 음수를 나타내는 이러한 방법은 이상하게 보이기도 하지만 몇 가지 장점을 가지고 있다. 장점은 다음과 같다.

첫 번째 장점으로 모든 8 비트(부호 비트 포함)의 이진 덧셈을 수행하고 완료되면 8비트에 맞지 않는 항목은 삭제하여 -1에서 -4를 더할 수 있다.

 

두 번째 장점으로 2의 보수 표현을 사용하면 음수의 비트를 양수처럼 왼쪽과 오른쪽으로 이동할 수 있으며 왼쪽으로 이동할 때마다 두배로 늘어나거나 오른쪽으로 이동할 땐 절반으로 줄어드는 것도 동일하게 사용할 수 있다. 이를 위해 부호 있는 정수가 오른쪽으로 이동할 때 추가적인 규칙이 사용된다. 부호 있는 정수를 오른쪽으로 이동할 때 부호 없는 정수와 동일한 규칙을 적용하되 왼쪽의 빈 비트를 부호 비트로 채우면 된다.

 

이렇게 하는 것은 부호가 있는 정수가 오른쪽으로 이동 한 뒤 동일한 부호를 가질 수 있도록 하며 이를 arithmetic shift라고 한다.

 

양수와 음수가 저장되는 특별한 방식 때문에 둘 중 하나를 오른쪽으로 이동하면 0에 가까워 지게 된다. 이동하는 동안 부호 비트를 동일하게 유지하는 것이 값이 0에 가까워질 때 음의 정수가 음수로 유지되는 것을 의미한다.


Overflow Operators

정수 상수나 변수에 해당 값에 보유할 수 없는 숫자를 삽입하려고 하면 Swift는 유효하지 않은 값 생성을 허용하지 않고 오류를 보고한다. 이러한 동작은 숫자가 너무 크거나 작은 것으로 작업할 때 안전성을 제공한다.

var potentialOverflow = Int16.max
// potentialOverflow equals 32767, which is the maximum value an Int16 can hold
potentialOverflow += 1
// this causes an error

위의 예를 보면 Int16은 -32768 ~ 32767 사이의 부호가 있는 정수를 가질 수 있다. 하지만 이를 벗어난 숫자로 설정하려는 순간 오류가 발생하게 된다.

 

값이 너무 크거나 작을 때 오류 처리를 제공하면 경계 값 조건을 코딩할 때 훨씬 더 많은 유연성을 얻을 수 있다.

 

그러나 오버플로 조건이 사용 가능한 비트 수를 자르도록 특별히 원하는 경우 오류를 트리거하는 대신 이 동작을 선택할 수 있다. Swift는 정수 계산을 위한 오버플로우 동작을 선택하는 세 가지 산술 오버플로우 연산자를 제공한다. 이러한 연산자는 &로 시작한다.

 

Overflow Addition &+

Overflow subtraction &-

Overflow multiplication &*

Value Overflow

숫자는 양의 방향과 음의 방향으로 오버플로우 될 수 있다.

var unsignedOverflow = UInt8.max
// unsignedOverflow equals 255, which is the maximum value a UInt8 can hold
unsignedOverflow = unsignedOverflow &+ 1
// unsignedOverflow is now equal to 0

위의 코드는 오버플로우 더하기 연산자 (&+)를 사용하여 부호가 없는 정수가 양의 방향으로 오버플로되도록 허용할 때 발생하는 상황의 예이다.

코드에서 보면 unsignedOverflow는 처음부터 UInt8이 가질 수 있는 최대값 즉 11111111로 초기화된다. 그런 뒤 오버플로우 더하기 연산자(&+)를 사용하여 1을 증가시키면 당연하게도 오버플로우가 발생한다. 그렇게 되면 위의 그림처럼 경계를 넘게 되어 UInt8의 값은 00000000 즉 0이 된다.

 

그럼 이번엔 오버플로우 빼기 연산자(&-)를 사용하는 예를 보자.

var unsignedOverflow = UInt8.min
// unsignedOverflow equals 0, which is the minimum value a UInt8 can hold
unsignedOverflow = unsignedOverflow &- 1
// unsignedOverflow is now equal to 255

위의 코드에서 unsignedOverflow는 UInt8이 가질 수 있는 최솟값인 00000000을 가지고 있다. 여기서 오버플로우 빼기 연산자(&-)를 사용하여 00000000에서 1을 빼면 오버플로우가 발생하게 되며 이때의 상황은 아래 그림과 같다.

위와 같이 오버플로우가 발생하여 11111111이 된다. 

 

부호가 있는 정수에서도 오버플로가 발생할 수 있는데 부호가 있는 정수의 모든 덧셈 뺄셈은 비트 방식으로 수행되며 부호 비트는 비트 왼쪽 및 오른쪽 시프트 연산자의 사용법에서 설명된 대로 더하거나 빼는 숫자의 일부로 포함된다.

var signedOverflow = Int8.min
// signedOverflow equals -128, which is the minimum value an Int8 can hold
signedOverflow = signedOverflow &- 1
// signedOverflow is now equal to 127

위의 코드에서 signedOverflow는 Int8이 가질 수 있는 최솟값인 10000000으로 초기화되었다. 여기에 오버플로 빼기 연산자(&-)를 사용하여 1을 빼면 01111111이 제공되며 부호 비트가 바뀌었으므로 Int8이 가질 수 있는 최댓값인 127을 가지게 된다. 이때 발생하는 상황은 아래 그림과 같다.

부호가 있는 정수와 부호가 없는 정수 모두 양수 방향으로의 오버플로우는 해당 자료형이 가질 수 있는 최솟값으로 돌아가고 음의 방향 오버플로우는 최솟값에서 최댓값으로 돌아가는 것을 볼 수 있었다.


Precedence and Associativity

연산자 우선순위는 일부 연산자에게 다른 연산자 보다 높은 우선순위를 부여한다. 따라서 여러 개의 연산자가 존재할 때 우선순위가 높은 연산자 부터 적용되게 된다. 

 

연산자 연관성은 우선순위가 동일한 연산자를 왼쪽에서 그룹화하거나 오른쪽에서 그룹화하는 방법을 정의한다.

 

여러개의 연산자가 있고 계산되는 순서를 계산할 때 각 연산자의 우선순위와 연관성을 고려하는 것이 중요하다. 간단한 예를 보며 이해해보자.

2 + 3 % 4 * 5
// this equals 17

만약 위의 식을 우선순위가 없다고 생각하면 답은 5가 될 것이다. 하지만 연산자 우선순위와 연관성 때문에 답은 5가 아닌 17이 나오게 된다. 위의 식에서는 %, * 연산자가 + 연산자보다 우선순위가 높다. 따라서 먼저 처리된다.

하지만 %,* 연산자의 경우 서로 동일한 우선순위를 갖는다. 이때 연관성이 적용되는데 나머지와 곱셈 연산은 모두 왼쪽에 있는 것부터 계산한다.

2 + ((3 % 4) * 5)

2 + (3 * 5)

2 + 15

즉 위와 같은 순서로 계산이 되기 때문에 답은 17이 나오게 된다.


Operator Methods

클래스와 구조체는 기존의 연산자를 자체적으로 구현할 수 있다. 이를 기존 연산자 오버 로딩(overloading the existing operators)라고 한다.

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)
    }
}

위의 코드는 구조체에서 더하기 연산자(+)를 구현한 것이다. 더하기 연산자는 두 대상에서 작동하기 때문에 이항 연산자이며 두 대상 사이에서 나타나기 때문에 중위라고 한다. 위의 코드에서는 2차원 위치 벡터 (x, y)에 대한 Vector2D 구조체를 정의한 뒤 더하기 연산자를 자체적으로 정의한다. 

 

연산자 메서드는 Vector2D에서 오버로드 할 연산자 (+)와 일치하는 메서드 이름을 가진 타입 메서드로 정의된다. 더하기는 벡터의 필수 동작이 아니기 때문에 Vector2D에 익스텐션으로 정의되었다.

 

연산자 메서드를 다시 보면 left, right 매개변수가 존재하며 이 두 매개변수의 값들을 각각 더해서 새로운 Vector2D 인스턴스를 반환하는 것을 볼 수 있다.

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)

위의 코드는 아까 정의한 연산자 메서드를 사용한 예이다.

위와 같이 2차원 벡터 2개가 더해져서 새로운 2차원 벡터를 만드는 것을 볼 수 있다.

Prefix and Postfix Operators

방금 위에서 본 예는 이항 중위 연산자를 구현한 것이었다. 중위 연산자 말고도 클래스와 구조체에서는 단항 연산자의 구현을 제공할 수도 있다. 단항 연산자는 단일 대상에서 작동하며 대상 앞의 오는 경우 prefix, 뒤에 오는 경우는 postfix 연산자라고 한다. 

 

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

위의 코드와 같이 연산자 메서드를 선언할 때 func 키워드 앞에 prefix, postfix 수정자를 작성하여 prefix, postfix 단항 연산자를 구현할 수 있다. 위의 코드에서는 Vector2D에 대한 단항 빼기 연산자를 구현했다. prefix를 func 앞에 써서 prefix 연산자로 정의한 것도 볼 수 있다. 여기서 구현한 단항 빼기 연산자는 값들에 -1을 곱한 값을 반환하도록 한다.

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

복합 할당 연산자는 =와 다른 연산과 결합한다. 예를 들어 +=는 더하기와 할당을 단일 연산으로 결합한다. 매개 변수의 값이 연산자 메서드 내에서 직접 수정되기 때문에 복합 할당 연산자의 왼쪽 입력 매개 변수는 inout으로 표시한다.

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)

위의 코드는 위에서 구현한 덧셈할당 연산자를 실제로 사용한 예이다.

 

참고로 기본 할당 연산자(=)는 오버 로딩할 수 없다. 또한 삼항 조건 연산자 (a? b:c)도 오버로딩 할 수 없다.

Equivalence Operators

기본적으로 사용자가 구현한 클래스와 구조체에는  == 연산자 및 != 연산자의 구현이 없다. == 연산자를 구현하는 방법에는 두 가지가 있다. 직접 구현하거나 여러 타입에 대한 Swift의 구현을 합성하도록 요청하는 것이다. 두 경우 모두 Equatable 프로토콜을 준수하도록 해야 한다.

 

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

위와 같이 == 연산자를 오버 로딩할 수 있다. 이제 2개의 Vector2D 인스턴스가 동일한지 확인할 수 있게 되었다!

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."

위의 코드는 구현한 == 연산자를 사용한 예이다.

 

많은 간단한 경우에 Adopting a Protocol using a Synthesized Implementation에 설명된 대로 Swift에 등가 연산자의 합성 구현을 제공하도록 요청할 수 있다.


Custom Operators

Swift에서 제공하는 표준 연산자 외에도 사용자가 연산자를 선언하고 구현할 수 있다. 이때 사용할 수 있는 문자 목록은 여기를 참고하면 된다.

 

새로운 연산자는 operator 키워드를 사용하여 전역 수준에서 선언되며 prefix, postfix, infix 수정자로 표시된다.

prefix operator +++

위와 같이 +++라는 새로운 prefix 접두사 연산자를 정의할 수 있다. 이 연산자는 Swift에서 기본적으로 없는 연산자이기 때문에 Vector2D 인스턴스 작업의 특정 컨텍스트에서 아래에 고유한 사용자 정의 의미가 부여된다. 

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)

위와 같이 새로 정의한 +++ 연산자는 아까 정의한 += 연산자를 사용하여 벡터의 값을 2배로 늘리는 연산자이다. 위의 코드에서 처럼 구현해서 실제 사용하는 것 까지 볼 수 있다.

Precedence for Custom Infix Operators

사용자가 직접 구현하는 infix 연산자는 각각 우선순위 그룹에 속한다. 우선 순위 그룹은 다른 infix 연산자와 관련된 연산자의 우선 순위와 연산자의 연관성을 지정한다.

 

우선 순위 그룹에 명시적으로 배치되지 않은 사용자 지정 infix 연산자에는 삼항 조건 연산자의 우선순위보다 즉시 우선순위가 높은 기본 우선순위 그룹이 제공된다. 

 

infix operator +-: AdditionPrecedence
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 연산자를 정의한다. 이 연산자는 두 벡터의 x 값을 더하고 첫 번째 벡터에서 두 번째 벡터의 y값을 뺀다.  본질적으로는 가산 연산자이기 때문에 +,-와 같은 가산 infix 연산자와 동일한 우선순위 그룹이 지정되었다. 연산자 우선순위 그룹 및 연관성 설정의 전체 목록을 포함하여 Swift 표준 라이브러리에서 제공하는 연산자에 대한 정보는 여기를 보면 된다.

 

Prefix, postfix 연산자를 정의할 때 우선순위를 지정하지 않는다. 그러나 동일한 피연산자에 prefix, postfix를 모두 적용하면 postfix 연산자가 먼저 적용된다.

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함