[최종 수정일 : 2018.09.13]
원문 : 애플 개발 문서 Swift 4.2 Language Guide - Advanced Operators
고급 연산자(Advanced Operators)
기본 연산자(Basic Operators)에서 설명된 연산자 외에, Swift는 더 복잡한 값을 다루기 위한 몇가지 고급 연산자를 제공합니다. 여기에는 C와 Objective-C에서 익숙한 모든 비트단위(bitwise)와 비트 쉬프트(bit shifting) 연산자가 포함됩니다.
C에서의 산술(arithmetic) 연산자와는 다르게, Swift에서의 산술 연산자는 기본적으로 오버플로우(overflow) 하지 않습니다. 오버플로우(overflow) 동작은 오류가 발생합니다. 오버플로우 동작 선택을 선택하기 위해, 오버플로우 추가 연산자(&+
)처럼, 기본적으로 오버플로우되는 Swift의 두번재 산술연산자 set
을 사용합니다. 이러한 모든 오버플로우 연산자는 &
으로 시작합니다.
자신만의 구조체, 클래스, 열거형을 정의할때, 사용자정의 타입에 대해 자신만의 표준 Swift연산자의 구현을 제공하는 것이 유용할 수 있습니다. Swift는 이러한 연산자의 맞춤형 구현을 제공하고 자신이 만든 각 타입에 대한 행동이 무엇인지 결정해야하는 것을 쉽게 해줍니다.
미리 정의된 연산자에만 국한되지 않습니다. Swift는 사용자정의 우선순위와 연관된 값으로 자신만의 사용자정의 중위(infix), 전위(prefix), 후위(postfix)와 할당연산자(=
)를 정의하는 자유를 줍니다. 이러한 연산자들은 미리 정의된 모든 연산자처럼 코드에서 사용되고 채택될수 있고, 여러분이 정의한 사용자정의 연산자를 지원하기 위해 기존 타입을 확장할 수 있습니다.
비트단위 연산자(Bitwise Operators)
비트단위 연산자(Bitwise operators)는 데이터 구조에서 개별적인 원시 데이터 비트를 관리하는 것이 가능합니다. 이것들은 그래픽 프로그래밍과 디바이스 드라이버 생성과 같은, 로우 레벨(low-level) 프로그래밍에서 사용됩니다. 비트단위 연산자는 사용자정의 프로토콜을 통한 통신을 위해 데이터를 인코딩(encoding)하고 디코딩(decoding)하는 것처럼, 외부 소스의 원시 데이터로 작업할때 유용할 수 있습니다.
아래 설명된 것처럼, Swift는 C에 있는 모든 비트단위 연산자를 지원합니다.
NOT 비트단위 연산자(Bitwise NOT Operator)
NOT 비트단위 연산자(bitwise NOT operator)(~
)은 숫자에 있는 모든 비트들을 반전(inverts) 시킵니다.
NOT 비트단위 연산자는 전위 연산자이고, 공백없이 연산하는 값 바로 앞에 나타납니다.
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // equals 11110000
UInt8
정수형은 8개의 비트를 가지고 0
부터 255
사이의 값을 저장할 수 있습니다. 이 예제는 UInt8
정수형을 처음 4개의 비트는 0
으로, 두번째 4개의 비트에는 1
로 설정하는 2진수(binary) 값 00001111
으로 초기화 합니다. 이것은 10진수(decimal) 값 15
와 같습니다.
NOT 비트단위 연산자는 initialBits
와 같지만, 모든 비트가 반전된 상수 invertedBits
를 만드는데 사용됩니다. 0은 1이되고, 1은 0이 됩니다. invertedBits
의 값은 부호없는 10진수(decimal) 값 240
과 같은 11110000
입니다.
AND 비트단위 연산자(Bitwise AND Operator)
AND 비트단위 연산자(bitwise AND operator)(&
) 는 두 숫자들의 비트를 결합합니다. 이것은 입력된 숫자 모두(both) 1
인 경우에만 1
로 설정하는 새로운 비트 값을 반환합니다.
아래 예제에서, firstSixBits
와 lastSixBits
값 모두 중간에 있는 4개의 비트가 1
입니다. AND 비트단위 연산자는 부호없는 10진수(decimal) 값 60
과 같은 00111100
숫자를 만들기 위해 결합합니다.
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits // equals 00111100
OR 비트 연산자(Bitwise OR Operator)
OR 비트 연산자(|
)는 두 숫자의 비트들을 비교합니다. 이 연산자는 입력된 숫자들의 비트에서 하나라도 1
인 경우에, 1
을 설정하는 새로운 비트 값을 반환합니다.
아래 예제에서, someBits
와 moreBits
의 값은 1
로 설정된 다른 비트를 가집니다. OR 비트단위 연산자는 부호없는 10진수 254
와 같은, 11111110
을 만들기 위해 결합합니다.
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits // equals 11111110
XOR 비트단위 연산자(Bitwise XOR Operator)
XOR 비트단위 연산자(bitwise XOR operator) 또는 "배타적인 OR 연산자(exclusive OR Operator)"
(^
)는 두 숫자들의 비트를 비교합니다. 이 연산자는 입력된 비트들이 다르면 1
을 설정하고 입력한 비트들이 같으면 0
을 설정하는, 새로운 비트 값을 반환합니다.
아래 예제에서, firstBits
와 otherBits
의 값은 서로 다른 비트에 1
을 설정합니다. XOR 비트단위 연산자는 출력값에서 비트들 모두 1
로 설정합니다. firstBits
와 otherBites
에 있는 모든 다른 비트들은 모두 일치하고 출력값에서 0
으로 설정합니다.
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // equals 00010001
비트단위 왼쪽과 오른쪽 시프트 연산자(Bitwise Left and Right Shift Operators)
비트단위 왼쪽 시프트 연산자(Bitwise left shift operators)(<<
)와 비트단위 오른쪽 시프트 연산자(Bitwise right shift operators)(>>
)는 숫자에 있는 모든 비트를 특정 숫자만큼, 왼쪽이나 오른쪽으로 이동시키며, 아래 정의된 규칙을 따릅니다.
비트단위 왼쪽과 오른쪽 시프트(Bitwise left and right shifts)는 정수를 곱하거(multiplying)나 나누는(dividing) 효과를 가지고 있습니다. 정수의 비트를 왼쪽으로 한칸씩 밀면(shiping) 값은 두배(doubles)가 되며, 오른쪽으로 한칸씩 밀면 값은 반절(halves)이 됩니다.
부호없는 연산자에 대한 시프트 동작(Shifting Behavior for Unsigned Integers)
부호 없는 정수형에 대한 비트 시프트(bit-shifting) 동작은 아래와 같습니다.
- 기존 비트들은 요청된 숫자만큼 왼쪽이나 오른쪽으로 이동됩니다.
- 정수형의 범위를 넘어서 이동된 모든 비트들은 버려집니다.
- 원본 비트들을 왼쪽이나 오른쪽이나 이동시킨 후에 비어 있는 곳에
0
이 삽입됩니다.
이러한 접근법을 논리적인 시프트(logical shift)이라고 합니다.
아래 그림은 11111111 << 1
(11111111
이 왼쪽으로 1
씩 이동)와 11111111 >> 1
(11111111
이 오른쪽으로 1
씩 이동) 결과를 보여줍니다. 파란색 숫자는 이동되며, 회색 숫자는 버려지고, 오랜지색은 0
이 삽입됩니다.
다음은 Swift코드로 비트 시프트(shifting)하는 것을 보여줍니다.
let shiftBits: UInt8 = 4 // 00000100 in binary
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
shiftBits >> 2 // 00000001
다른 데이터 타입으로 인코딩하고 디코딩하기 위해 비트 시프트를 사용할 수 있습니다.
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
이 예제는 분홍색 CSS(Cascading Style Sheets) 색상 값을 저장하기 위해 UInt32
상수 pink
를 사용합니다. CSS 색상 값 #CC6699
는 Swift1 6진수(hexadecimal) 숫자 0xCC6699
로 표현됩니다. 이 색상은 AND 비트단위 연산자(&
)와 비트단위 왼쪽 시프트 연산자(>>
)를 사용해서 빨강(CC
), 녹색(66
), 파랑(99
) 성분으로 분해됩니다.
빨강 구성요소(component)는 0xCC6699
와 0xFF0000
숫자들간에 AND 비트단위 연산을 수행해서 얻어집니다. 0xFF0000
에서 0은 두번재와 세번째 바이트들에 마스크(mask)
효과로 6699
가 무시되고 결과적으로 0xCC0000
이 남게됩니다.
이 숫자는 오른쪽으로 16자리만큼 밀리게됩니다(shifted) (>> 16
). 16진수 숫자에서 각 문자들은 8비트를 사용하며, 오른쪽으로 16만큼 이동하면 0xCC0000
이 0x0000CC
로 변경될 것입니다. 이것은 10진수 값 204
을 가지는 0xCC
와 같습니다.
비슷하게, 녹색 구성요소는 0xCC6699
와 0x00FF00
숫자간에 AND 비트단위 연산을 수행해서 결과 값 0x6600
이 얻어집니다. 그리고나서 이러한 출력 값은 오른쪽으로 8자리만큼 밀리게 되며(shifted), 10진수 값 102
인 0x66
의 값이 주어집니다.
마지막으로, 파랑 구성요소는 0xCC6699
와 0x0000FF
숫자간에 AND 비트단위 연산을 수행해서 결과값 0x000099
가 얻어집니다. 0x000099
는 이미 10진수 값 153
인 0x99
와 같으므로 오른쪽으로 밀(shift) 필요가 없습니다.
부호있는 정수형에 대한 시프트 동작(Shifting Behavior for Signed Integers)
부호 있는 정수형은 2진수로 표현되는 방식 때문에,부호가 없는(unsigned) 정수형 보다 부호가 있는(signed) 정수형의 시프트(shifting) 동작은 더 복잡합니다. (아래 예제는, 간단하게 8비트로 된 부호있는 정수형이지만, 모든 크기의 부호 있는 정수형에 적용되는 원칙은 같습니다 )
부호 있는 정수형은 첫번째 비트(부호비트(sign bit))를 이 정수형이 양수(positive)인지 음수(negative)인지 가리키기 위해 사용합니다. 부호 비트 0
은 양수를 의미하고, 부호 비트 1
은 음수를 의미합니다.
남아있는 비트들(값 비트(value bits))에 실제 값을 저장합니다. 양수는 부호 없는 정수형과 같은 방법으로 저장되며, 0
부터 게산합니다.
다음은 숫자 4
에 대한 Int8
비트 내부를 보여줍니다.
부호 비트가 0
(양수
를 의미)이고, 7개의 값 비트는 숫자 4
이며, 2진수 표기법으로 작성되었습니다.
하지만 음수는, 다르게 저장됩니다. 2
의 n
제곱승(power) 에서 절대값을 빼서 저장되며, n
은 값 비트 개수입니다. 8비트 숫자는 7개의 값 비트를 가지며, 2
의 7
제곱승 또는 128
을 의미합니다.
다음은 숫자 -4
에 대한 Int8
비트 내부를 보여줍니다.
이번에는, 부호 비트가 1
(음수
를 의미)이고, 7개의 값 비트는 124
의 2진 값을 가지고 있습니다 (128 - 4
)
음수 숫자에 대한 인코딩은 2의 보수(two’s complement) 표현법이라고 합니다. 음수를 표현하는 것이 이상하게 보일수 있지만, 몇가지 장점이 잇습니다.
첫번째로, -4
에 -1
을 더할 수 있으며, 단순하게 모든 8개의 비트들(부호 비트를 포함해서)의 표준 이진 덧셈을 수행하고, 계산이 완료되면 8비트에 맞지 않는 것들을 버립니다.
두번째로, 2의 보수 표현법은 음수의 비트들을 왼쪽과 오른쪽으로 밀고(shift), 왼쪽으로 밀었을때 그 값이 여전히 두배가 되거나, 오른쪽으로 밀었을때에는(shift) 반절이 됩니다. 이를 위해서, 부호있는 정수를 오른쪽으로 밀때(shifted) 추가 규칙이 사용됩니다 : 부호있는 정수를 오른쪽으로 밀때(shift), 부호 없는 정수형과 같은 규칙이 적용되지만, 왼쪽에 비어있는 비트들을 0
보다는 부호 비트(sign bit)로 채웁니다.
이 동작은 부호 있는 정수형이 오른쪽으로 밀린(shifted)뒤에도 같은 부호를 가지도록 보장해 주고 산술 시프트(arithmetic shift)라고 합니다.
양수와 음수가 저장되는 특별한 방법때문에, 그것들 중 하나를 오른쪽으로 밀어(shifting)서 이동하면 0
에 가까워 집니다. 부호 비트를 유지하는 것은 미는중(shift)에도 값이 0
에 가까워짐에 따라, 음수의 정수형이 음수로 남아있는 것을 의미합니다.
오버플로우 연산자(Overflow Operators)
정수형 상수나 변수에 가질수 없는 값을 삽입하려고 하면, Swift는 기본적으로 유효하지 않는 값을 만드는 것을 허용하기 보다는 오류를 발생시킵니다. 이 동작은 너무 크거나 작은 숫자로 작업할때 추가적인 안정성을 제공합니다.
예를 들어, Int16
정수형 타입은 -32768
과 32767
사이의 모든 부호있는 정수를 가질수 있습니다.범위를 벗어난 숫자로 Int16
상수나 변수를 설정하려고 하면 오류가 발생합니다.
var potentialOverflow = Int16.max
// potentialOverflow equals 32767, which is the maximum value an Int16 can hold
potentialOverflow += 1
// this causes an error
너무 크거나 너무 작은 값을 가질때 오류 처리를 제공하는 것은 경계값 조건에 대해 코딩할때 훨씬 더 융통성이 있습니다.
하지만, 사용가능한 비트를 줄이기 위해 오버플로우 조건이 필요할때, 오류를 발생시키는 대신에 이 동작을 선택할 수 있습니다. Swift는 정수형 계산에 대한 오버플로우 동작을 선택하는 3가지 산술 오버플로우 연산자(overflow operators)를 제공합니다. 이러한 연산자들은 언제나. &
으로 시작합니다.
- 오버플로우 더하기 (
&+
) - 오버플로우 빼기 (
&-
) - 오버플로우 곱하기 (
&*
)
값 오버플로우(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
이 가질수 있는 최대 값(255
또는 이진수 11111111
)으로 초기화 됩니다. 그리고나서 오버플로우 더하기 연산자(&+
)를 사용해서 1씩 증가시킵니다. 이것은 UInt8
이 가질수 있는 크기 이상의 이진(binary) 표현을 밀어넣어(pushes), 아래 그림에서 보는 것처럼, 범위를 넘어서 오버플로우가 발생합니다. 오버플로우 더하기 하고 난 후에 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
UInt8
이 가질수 있는 최소 값은 0
또는 이진수 00000000
입니다. 오버플로우 빼기 연산자(&-
)를 사용해서 00000000
에서 1
을 빼는 경우에, 숫자는 오버플로우 되고 11111111
또는 10진수 255
가 될 것입니다.
또한, 오버플로우는 부호 있는 정수형에서도 발생합니다. 비트단위 왼쪽과 오른쪽 시프트 연산(Bitwise Left and Right Shift Operators)에서 설명된 것 처럼, 부호 있는 정수형에 대한 모든 더하기와 빼기는 더하거나 빼는 숫자와 부호비트를 포함해서 비트단위로 수행됩니다.
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
Int8
이 가질수 잇는 최소 값은 -128
또는 이진수 10000000
입니다. 오버플로우 연산자로 이진수에서 1
을 뺀 이진 값은 01111111
이며, 부호 비트와 양수 127
을 토글(toggles)시키며, Int8
이 가질수 있는 최대 양수값입니다.
부호가 있고 부호가 없는 정수형 모두, 양수 방향으로 오버플로우가 발생하면 정수의 유효한 최대 값에서 최소 값까지 래핑(wraps)되고, 수 방향으로 오버플로우가 발생하면 최소 값에서 최대값까지 랩핑합니다.
우선순위와 연관성(Precedence and Associativity)
연산자 우선순위(precedence)는 다른 연산자보다 더 높은 우선순위를 줍니다. 이러한 연산자 먼저 적용됩니다.
연산자 연관성(associativity)은 같은 우선순위의 연산자들을 함께 그룹화하는 방법을 정의합니다 - 왼쪽에서 부터 그룹화되거나, 오른쪽으로 부터 그룹화. 왼쪽에 있는 표현식과 연관있다
또는 오른쪽에 있는 표현식과 연관있다
라는 의미로 생각합니다.
복합 표현식이 계산될 순서를 결정할때, 각각 연산자의 우선순위와 연관성을 고려하는 것은 중요합니다. 예를 들어, 연산자 우선순위는 다음 표현식이 왜 17
이 되는지 설명합니다.
2 + 3 % 4 * 5
// this equals 17
왼쪽에서 오른쪽으로 정확히 읽으면, 다음과 같이 계산된 표현식을 예상할 수 있습니다.
2
더하기3
은5
5
나머지4
는1
1
곱하기.5
는5
하지만, 실제 답은 5
가 아니라 17
입니다. 높은 우선순위 연산자가 낮은 우선순위 전에 처리됩니다. Swift에서는 C 처럼, 나머지 연산자(%
)와 곱하기 연산자(*
)는 더하기 연산자(+
)보다 더 높은 우선순위를 가집니다. 결과적으로, 더하기를 구하기 전에 둘다 처리 됩니다.
하지만, 나머지(remainder)와 곱하기(multiplication)는 각기 서로 같은(same) 우선순위를 가집니다. 정확한 순서로 처리하려면, 연관성(associativity)을 고려해야 합니다. 나머지와 곱하기 모두 왼쪽에 있는 표현과 연관(associate)되어 있습니다. 왼쪽에서 시작하는, 이러한 표현식에 암시적으로 괄호(()
)가 추가 된 것으로 생각합니다.
2 + ((3 % 4) * 5)
(3 % 4)
는 3
이며, 다음과 같습니다.
2 + (3 * 5)
(3 * 5)
는 15
이며, 다음과 같습니다.
2 + 15
이 계산은 마지박 값 17
을 산출(yields)합니다.
Swift 표준 라이브러리에서 제공된 연산자에 대한 자세한 정보는, 연산자 우선순위 그룹의 전체 목록과 연관성 설정은, 연산자 선언하기(Operator Declarations)를 보세요.
주의
Swift의 연산자 우선순위와 연과성 규칙은 C와 Objective-C 보다 간단하고 더 예측 가능합니다. 하지만 , C 기반의 언어와 정확히 같지 않다는 것을 의미합니다. 기존 코드를 Swift로 이식(porting)할때 의도한 방식대로 연산자 동작이 작동하도록 주의해야 합니다.
연산자 메소드(Operator Methods)
클래스와 구조체는 기존 연산자를 자체적으로 구현할 수 있습니다. 이것은 기존 연산자를 오버로딩(overloading)한다라고 합니다.
아래 에제는 사용자정의 구조체에 대해 산술 더하기 연산자(+
) 구현하는 방법을 보여줍니다. 산술 더하기 연산자는 2개의 대상에 대해서 동작하기 때문에, 2항 연산자(binary operator)이고 2개의 대상 사이에 나타나기 때문에, 중위(infix)라고 합니다.
예제는 2차원 위치 벡터(x, y)
에 대한Vector2D
구조체를 정의하며, 뒤이어 Vector2D
구조체 인스턴스를 더하는 연산자 메소드(operator method)를 정의합니다.
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)
}
}
연산자 메소드는 Vector2D
에서 오버로드될 연산자와 일치하는 메소드 이름(+
)으로, 타입 메소드처럼 정의됩니다. 더하기는 벡터에 대한 필수 동작이 아니기 때문에, 타입 메소드는 Vector2D
의 메인 구조체 선언 보다는 Vector2D
의 확장에서 정의됩니다. 산술 더하기 연산자는 2항 연산자 이기 때문에, 이 연산자 메소드는 Vector2D
타입의 입력 매개변수 2개를 받고 Vector2D
타입의 출력 값 하나를 반환 합니다.
이 구현에서, Vector2D
인스턴스를+
연산자의 왼쪽과 오른쪽을 표현하기 위해 left
와 right
이름으로된 입력 매개변수를 가집니다. 이 메소드는 새로운 Vector2D
인스턴스를 반환하며, x
와 y
프로퍼티는 함께 추가된 2개의 Vector2D
인스턴스의 x
와 y
프로퍼티의 합으로 초기화 됩니다.
타입 메소드는 기존 Vector2D
인스턴스간에 중위(infix) 연산자 처럼 사용될 수 있습니다.
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)
이 예제는 아래 그림처럼, (5.0, 5.0)
벡터를 만들기 위해 (3.0, 1.0)
과 (2.0, 4.0)
벡터들을 함께 더합니다.
전위와 후위 연산자(Prefix and Postfix Operators)
위 예제는 2항 중위 연산자(binary infix operator)의 사용자정의 구현한 것을 보여줍니다. 클래스와 구조체는 표준 단항 연산자(unary operators)구현을 제공할 수 있습니다. 단항 연산자(Unary operators)는 단일 대상에서 동작합니다. 그것은 대상 앞에 있는 것은(-a
) 전위(prefix)이고 대상의 뒤에 있는 것은(b!
) 후위(postfix) 연산자 입니다.
연산자 메소드를 선언할때 func
키워드 앞에 prefix
나 postfix
수식어를 작성해서 전위(prefix)나 후위(postfix) 단항 연산자(unary operator)를 구현합니다.
extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
}
위 예제는 Vector2D
인스턴스에 대한 단항 빼기 연산자(-a
)를 구현합니다. 단항 빼기 연산자는 전위(prefix) 연산자이고, 이 메소드는 prefix
수식어를 사용할 자격이(qualified)있습니다.
간단한 숫자 값의 경우, 단항 빼기 연산자는 양수를 음수로 변환하고 반대의 경우도 마찬가지입니다. Vector2D
인스턴스에 해당하는 구현은 x
와 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)는 할당(=
)과 다른 연산자를 결합합니다. 예를 들어, 더하기 할당 연산자(+=
)는 더하기와 할당하는 것을 하나의 동작으로 결합합니다. 매개변수 값들이 연산자 메소드 안에서 수정되야 하기 때문에, 복합 할당 연산자의 왼쪽 입력 매개변수의 타입은 inout
으로 표시합니다.
아래 예제는 Vector2D
인스턴스에 대해 더하기 할당 연산자 메소드를 구현한 것입니다.
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)
주의
기본 할당 연산자(=
)를 오버로드(overload)하는 것은 불가능합니다. 복합 할당 연산자만 오버로드(overloaded)할 수 있습니다. 3항 복합 연산자 (a ? b : c
)는 오버로드 할 수 없습니다.
등가 연산자(Equivalence Operators)
기본적으로, 사용자정의 클래스와 구조체는 등가 연산자(equivalence operators)의 기본 동작을 사용하지 못하며, 같음(equal to) 연산자(==
)와 같지 않음(not equal to) 연산자(!=
)로 알려져 있습니다.
사용자정의 타입이 같은지(equivalence) 검사히기 위해 등가 연산자(equivalence operators) 를 사용하며, 다른 중위 연산자와 같은 방법으로 같음(equal to)
연산자의 구현을 제공하고, 표준 라이브러리의 Equatable
프로토콜을 준수하도록 추가합니다.
extension Vector2D: Equatable {
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
}
위 예제는 2개의 Vector2D
인스턴스가 같은 값을 가지는지 검사하기 위한 같음(equal to)
연산자 (==
)를 구현합니다. Vector2D
의 문맥상(context), 인스턴스 모두 같은
를 의미하는 x
값과 y
값을 가지고 있다같음(equal)
이라고 생각하고, 이 로직은 연산자 구현에 의해 사용됩니다. 같음(equal to)
연산자를 구현하는 경우, 일반적으로 같지 않음(not equal to)
연산자(!=
) 구현은 필요하지 않습니다. 표준 라이브러리는 구현한 같음(equal to)
연산자의 결과를 단순히 반대하는(negates), 같지 않음(not equal to)
연산자의 기본 구현을 제공합니다.
이제, 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."
많은 간단한 경우에, Swft에게 등가 연산자의 합성된(synthesized) 구현을 제공하도록 요청할 수 있습니다. Swift는 다음에 오는 사용자정의 타입 종류에 대해 합성된 구현을 제공합니다.
Equatable
프로토콜을 준수하는 저장 프로퍼티만 가지는 구조체Equatable
프로토콜을 준수하는 연관된 타입만 가지는 열거형- 연관된 타입이 없는 열거형
이러한 구현을 사용하기위해(receives) 원래 선언이 포함된 파일에서 Equatable
적합성(conformance) 선언합니다.
아래 예제는 3차원(three-dimensional) 위치 벡터(x, y, z)
에 대한 구조체 Vector3D
정의하며, Vector2D
구조체와 비슷합니다. x, y, z
프로퍼티는 모두 Equatable
타입이기 때문에, Vector3D
는 등가 연산자의 기본 구현을 사용합니다.
struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0
}
let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
print("These two vectors are also equivalent.")
}
// Prints "These two vectors are also equivalent."
사용자정의 연산자(Custom Operators)
Swift에서 제공하는 표준 연산자외에도 사용자정의 연산자(custom operators)를 선언하고 구현할 수 있습니다. 사용자정의 연산자를 정의하기 위해 사용될수 있는 특징들에 대한 목록은 연산자(Operators)를 보세요.
새로운 연산자는 operator
키워드를 사용해서 전역 레벨에서 선언되고, prefix, infix, postfix
수식어로 표시됩니다.
prefix operator +++
위 예제는 새로운 전위 연산자(prefix operator) +++
를 정의합니다. 이 연산자는 Swift에 존재하지 않고, Vector2D
인스턴스로 작업하는 특정 상황(context)에서 자체적인 사용자정의 의미를 부여 받습니다. 이 예제의 목적을 위해, +++
는 새로운 prefix doubling
연산자처럼 처리됩니다. 이전에 정의된 더하기 할당연산자로 그 자체에 벡터를 대해서, Vector2D
인스턴스의 x
와 y
값을 2배로 만듭니다. +++
연산자 구현을 위해, 다음과 같이 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)
사용자정의 중위 연산자에 대한 우선순위(Precedence for Custom Infix Operators)
사용자정의 중위 연산자(custom infix operators)들은 각각 우선순위 그룹에 속해있습니다. 우선순위 그룹은 연산자의 연관성(associativity) 뿐만아리라, 다른 infix
연산자와 관련하여 우선순위를 지정합니다. 이러한 특성들이 중위 연산자와 다른 중위 연산자와 영향을 주는지에 대한 설명은 우선순위와 연관성(Precedence and Associativity)를 보세요.
우선순위 그룹에 명시적으로 배치하지 않은 사용자정의 중위(infix)
연산자는 3항 조건 연산자(ternary conditional operator)의 우선순위보다 더 높은, 기본 우선순위 그룹이 지정됩니다.
아래 예제는 우선순위 그룹 AdditionPrecedence
에 속하는 새로운 중위(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)
이 연산자는 두 벡터의 x
값을 더하고, 첫번째 벡터에서 두번째 벡터의 y
값을 빼줍니다. 이것은 본질적으로 더하는(additive)
연산자 이기때문에, +
와 -
처럼, 더하기 중위 연산자(additive infix operators)와 같은 우선순위 그룹이 주어집니다. Swift 표준 라이브러리에 의해 제공되는 연산자에 대한 정보, 연산자 우선순위 그룹과 연관성(associativity) 설정의 전체 목록을 보려면, 연산자 선언(Operator Declarations)를 보세요. 우선순위 그룹에 대한 자세한 내용과 자신만의 연산자와 우선순위 그룹을 정의하는 문법을 보려면, 연산자 선언(Operator Declaration)을 보세요.
주의
전위(prefix)나 후위(postfix) 연산자를 정의할때는 우선순위를 지정하지 않습니다. 하지만, 전위(prefix)와 후위(postfix) 연산자 모두 동일한 피연산자(operand)인 경우에, 후위(postfix) 연산자가 먼저 적용됩니다.
'Swift > Language Guide' 카테고리의 다른 글
불분명한 타입(Opaque Types) (0) | 2019.12.12 |
---|---|
컬렉션 타입(Collection Types) (0) | 2019.03.05 |
문자열과 문자(Strings and Characters) (0) | 2019.02.28 |
기본 연산자(Basic Operators) (0) | 2019.02.26 |
Access Control (0) | 2018.09.18 |
Memory Safety (0) | 2018.09.18 |
Automatic Reference Counting (0) | 2018.09.18 |
Generics (0) | 2018.09.18 |