Swifter {Swift Developer}

메뉴

5. 숫자 리터럴과 연산자

[vc_row][vc_column][vc_column_text]이번장에서는 숫자 리터럴은 “1234” 및 “-100”, “0xff00”등의 정수 리터럴, “3.14” 및 “314e-1”등의 부동소수점 리터럴이 있습니다. 연산자는 Objective-C언어등을 사용해본 독자들라면 알고 있는 “+”, “/”, “==”등의 기호를 말합니다.

다만 Swift언어가 Objective-C언어 사용자들이 넘어오기 편하도록 하기 위해 기본적으로 C언어 및 Objective-C언등의 정수 및 상수값, 연산자가 거의 동일합니다. 그러나 숫자의 형 및 연산은 C언어 및 JavaScript와 비슷하지만, 일부 다른 것도 있기 때문에 주의해야 합니다.

규칙적인 부분으로는 암시적 형변환은 없기 때문에 개발자가 명시적으로 형을 맞춰야 하며, 숫자 리터럴은 형을 가지지 않습니다. 그리고 단항 연산자(“!” 및 “+”)은 변수사이에 공백을 넣는 것을 금지하고 있습니다.[/vc_column_text][vc_separator][vc_custom_heading text=”(1) 숫자 리터럴” use_theme_fonts=”yes”][vc_column_text]

정수 리터럴

정수 리터럴은 C언어와 유사하지만 8진수 표기는 C언어와 다릅니다. 10진수는 접두사가 없지만 2진수, 8진수, 16진수는 아래와 같이 표현합니다.

  • 2진수: “0b”를 앞에 붙이고 0과 1로 이루어진 열
  • 8진수: “0o”을 앞에 붙이고 0~7로 이루어진 열
  • 16진수: “0x”를 앞에 붙이고 0~9, a~f(대문자도 가능)으로 이루어진 열

이에 대한 이해를 높이기 위해 아래 예제를 참조합시다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
1_234 // "_"은 무시됨, 결과: 1234
0b1111 // 결과: 15
0o770 // 결과: 504
0x123 // 결과: 291
019 // 숫자 앞에 0이 있다고 해서 8진수로 해석하지 않음, 결과: 19
1____3 // "_"은 무시됨, 결과: 13
[/code]

[예제 2-30] 정수 리터럴[/vc_column_text][vc_column_text]

부동소수점 리터럴

Swift언어에서는 C언어에서 사용하는 “3.14”와 “0.314e + 1”형태의 10진수와 지수를 결합한 형태 및 16진수와 지수 조합 형태가 도입되어 있습니다. 다만, 16진수 기수는 10대신 2로 하기 때문에 주의해야 합니다. 예로 “0x12.8p0”은 10(16진수) – 16, 2, 0,.8 (16진수) – 0.5에서 지수2이기 때문에 10진수로 표현하면 18.5 이 나옵니다. 이를 좀더 직관적으료 표현한 그림을 살펴보시고 이해하시기 바랍니다.[/vc_column_text][vc_single_image image=”845″ img_size=”full” alignment=”center”][vc_column_text]그럼 부동소수점 리터럴 표기에 대한 예제를 살펴봅시다. 앞에서 이야기한 정수 리터럴처럼 “_”은 무시됩니다.

[code lang=”swift”]
0.314e+2 // 결과: 2.314, 0.314 x 100
3_14e-1 // 결과: 31.4, "_"은 무시하고 314 / 10
0x12.8p0 // 결과: 18.5, 위 그림 참조
0x12.8p-1 // 결과: 9.25, 18.5 / 2
[/code]

[예제 2-31] 부동소수점 리터럴[/vc_column_text][vc_custom_heading text=”(2) 연산자” use_theme_fonts=”yes”][vc_column_text]

대입연산자

대입 연산자 x=y는 ‘y값을 변수 x에 대입한다”라는 의미에서 C언어와 유사한 형태의 연산자입니다. 다만, C언어와 다른 점은 대입 연산자는 대입한 값을 리턴핮 ㅣ않기 때문에 “x = y =z = 10”형태로 할당할 수 없습니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x = 10 // 10
let y = 100 // 100
x = y // 100, 변수 x에 y값(100) 대입
[/code]

[예제 2-32] 대입 연산자 예제[/vc_column_text][vc_column_text]튜플에서는 여러개의 변수에 값을 할당 할수도 있습니다.

[code lang=”swift”]
var width: Int, radius: Double

(width, radius) = (123, 3.14)
[/code]

[예제 2-33] 튜플을 사용한 대입 예제[/vc_column_text][vc_column_text]위 예제는 변수선언과 튜플 이용을 따로 선언한 형태인데 이를 좀더 심플하게 변수선언과 초기화를 할 때 튜플을 이용하는 방법이 있습니다.

var (width, radius) = (123, 3.14)

 

선언시 변수형

var x = 10 에서 JavaScript처럼 변수형이 없는것 같지만, 앞에서 이야기했듯이 Swift언어에서는 변수 선언시 형추론을 통해 형이 확정됩니다. 대입 연산자는 대입되는 변수형을 유지하기 위해 호환되지 않는 값 대입은 오류가 나게 됩니다.

var x = 10

x = “하하하” // Int형 변수 x에 String값을 할당할 수 없기 때문에 오류가 남

단, 숫자 변수에 숫자 리터럴을 할당한다면 약간 다릅니다. 숫자 리터럴은 형을 가진 것이 아니기 때문에 리터럴 정수나 부동소수점 모두 변수형에 맞게 할당됩니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x = 3 // 변수 x는 Int형으로 선언
x = 3.14 // x는 Int형이기 때문에 부동소수점 값을 대입할수 없음
var y = 3.14 // 변수 y는 Double형으로 선언
y = 3 // y는 Double형이기 때문에 정수 리터럴 1을 Double형 1.0으로 대입가능
[/code]

[예제 2-34] 숫자형 변수에 숫자 리터럴 할당할 경우[/vc_column_text][vc_column_text]위 예제는 리터럴에 대해 암시적 캐스트가 Objective-C언어처럼 실행되는 것을 보여주지만 약간 다릅니다. 그렇다면 좀더 이해를 돕기 위해 다른 예를 보여드리겠습니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x = 10 // 결과: 10, 변수x는 Int형으로 선언
var y = x + 0.1 // 결과: 오류, Int형과 Double형은 연산안됨
var z = 10 + 0.1 // 결과: 10.1, 부동소수점 리터럴에 의해 초기 변수형이 Double로 지정
[/code]

[예제 2-35] 다른 결과에 대한 예제[/vc_column_text][vc_column_text]위 예제에서 y의 값은 10.1이 안된다는 점에서 주의해야 합니다. x는 Int에서 0.1의 Double형과 암시적 캐스트되지 않기 때문에 연산오류가 발생합니다. 또한 z는 정수리터럴(10)과 부동수소점 리터럴(0.1)의 계산결과는 부동수소점 리터럴로 처리되어 결과가 z변수형이 Double로 결정됩니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x = 10 // 변수x는 Int형
var y = 0.1 // 변수y는 Double형
var z = x + y // 결과: 오류, Int형과 Double은 연산될 수 없음
[/code]

[예제 2-36] 암시적인 캐스트가 없어 발생하는 오류[/vc_column_text][vc_column_text]그리고, 변수 선언시, 초기값을 선언하지 않는 경우에는 형을 지정해주는 것을 추천합니다.

var x : Int    // 초기값은 선언되어 있지 않지만 Int형으로 선언함

 

산술 연산자

산술 연산자는 더하기(+), 빼기(-), 곱하기(*), 나누기(/), 나머지(%)로 Objective-C언어나 C언어와 비슷합니다. 이 또한, 다른 형으로 선언된 변수끼리 연산은 안됩니다. 아래 예제는 Int형 연산을 보여줍니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
z = x + y // 결과: 28
z = x – y // 결과: 10
z = x * y // 결과: 171
z = x / y // 결과: 2
z = x % y // 결과: 1
[/code]

[예제 2-37] Int형 산술 연산[/vc_column_text][vc_column_text]C언어등에서는 0을 나누게 되면 런타임 오류가 발생하지만, Swift언어에서는 오버플로우나 언더플로우가 발생해도 런타임 오류가 발생하지 않습니다. 그리고 나중에 런타임 오류를 발생하지 않는 오버플로우 연산자에 대해서는 따로 다루겠습니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x = 1 << 63 // -9223372036854775808
var y = x + x // 오버플로우 실행시 오류
[/code]

[예제 2-38] 오버플로우 예제[/vc_column_text][vc_column_text]연산자 +는 문자열(String)과 배열(Array)에 대해서는 연결한다는 의미로 사용됩니다. 나중에 문자열 사용에 대해서 설명할 때 좀더 자세히 설명하겠지만 일단 간단하게 살펴보면 다음과 같습니다.

“안녕” + “하세요”   // 결과: “안녕하세요”

[10] + [100, 1000]    // 결과: [10.100,1000]

연산자 %는 C언어와는 다르게 Double값에도 사용할 수 있지만, 다음과 같은 공식 “(x/y)*y+(x%b)=x”는 성립되지 않기 때문에 주의해야 합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x = 19, y = 9
(x / y) * y + (x % y) // 결과: 19, Int형인 경우 가능

var n = 19.0, m = 9.0
(n / m) * m + (n % m) // 결과: 20, Double형인 경우 n / m이 2.1111111…이기 때문에 안됨
[/code]

[예제 2-39] %연산자 사용시 주의사항 예제[/vc_column_text][vc_column_text]

비트 연산자 비트시프트 연산자

정수에 대한 비트연산자 “~”(NOT), “&”(AND), “|”(OR), “^”(XOR)은 C언처럼 거의 동일합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x: UInt8 = 0x00, y: UInt8 = 0x11
~x // 255
x & y // 0
x | y // 17
x ^ y // 17
[/code]

[예제 2-40] 비트 연산자 예제[/vc_column_text][vc_column_text]정수값에 대한 비트 시프트 “<<”(왼쪽 비트 시프트), “>>”(오른쪽 비트 시프트) 실행 형태는 Objective-C와 비슷합니다. 이는 C언어에서는 오른쪽 시프트가 산술 시프트인지 논리적 시프트인지 정의되어 있지 않지만, Objective-C는 산술 시프트입니다. 이 말은 오른쪽 시프트결과 부호가 없는 정수값은 왼쪽비트에 0이 들어가고 부호가 있는 정수값은 왼쪽비트 부호 비트값이 포함됩니다.

그럼 Objective-C언어의 비트 시프트 연산결과와 Swift언어의 비트 시프트 연산결과를 비교해봅시다.[/vc_column_text][vc_column_text]

[code lang=”objc”]
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
@autoreleasepool {

signed short x = 0x2222;
unsigned short y = 0x3333;

NSLog(@"%04x %04x", x >> 2, y >> 2);
// 0888
// 0ccc
}
return 0;
}
[/code]

[예제 2-41] Objective-C언어의 비트시프트 연산 예제[/vc_column_text][vc_column_text]동일한 비트 시프트 연산을 Swift언어에서 실행한 결과입니다.

[code lang=”swift”]
var x: Int16 = (0x1111 << 1), y: UInt16 = 0x3333 String(format: "%x", x >> 2) // 888
String(format: "%x", y >> 2) // ccc
[/code]

[예제 2-42] Swift언어의 비트시프트 연산 예제[/vc_column_text][vc_column_text]비교 연산자

비교 연산자는 논리값(true/false)를 리턴합니다. C언어에서도 사용하던 “==”, “!=”, “<”, “>”, “<=”,”>=”은 그대로 Swift언어에서도 사용하고 “===”, “!==”가 추가되었습니다.

“===”와 “!==” 비교 연산자는 두 변수가 같은 객체를 참조하는지를 구분할 때 사용하는 것으로 비교 대상은 클래스의 인스턴스이어야 합니다.

 

논리 연산자

논리 연산자는 “&&”(논리AND), “||”(논리OR), “!”(논리NOT)는 C언어때부터 나왔던 연산자를 그대로 사용하지만, C언어처럼 정수가 항상 논리값으로 사용할 수 있는 것은 아닙니다.  Swift언어의 논리 연산자에서는 true/false라는 값만 사용합니다. 또한 “!” 단항 연산자에서는 변수 사이에 공백이 있으면 안됩니다.

 

삼항 연산자

삼항 연산자는 “조건 ? 식1 : 식2”로 구성된 연산자로 C언어를 알고 있다면 이미 알고 있는 연산자이지만 조건 부분에서 Bool로 체크해야 한다는 것만 기억하시면 됩니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x: Bool = true
let y = x ? 0 : 20 // x가 true이면 y = 0이 됨
y + 1 // 1
let z = x ? 0 : "한글" // z의 형 추론을 할 경우 NSObject가 됨
z + 1 // +연산자는 NSObject에 정의안되어 있기 때문에 컴파일 오류남
[/code]

[예제 2-43] 삼항 연산자 예제[/vc_column_text][vc_column_text]

복합 대입 연산자 / 증가 감소

복합 대입 연산자 “+=”(덧셈 대입), “-=”(빼기 대입), “*=”(곱셈 대입), “/=”(나누기 대입), “%=”(나머지 대입), “<<=”(왼쪽시프트 대입), “>>=”(오른쪽시프트 대입), “&=”(AND 대입), “^=”(XOR 대입), “|=”(OR 대입), “&&=”(논리AND 대입), “||=”(논리OR 대입)은 C언어와 동일하지만 대입한 결과값이 리턴되지 않는다는 점에서 대입 연산자와 비슷합니다.[/vc_column_text][vc_custom_heading text=”(3) Swift 언어만의 연산자” use_theme_fonts=”yes”][vc_column_text]

오버플로우 연산자

일반적인 계산에서 오버플로우가 발생하면 안전성을 위해 예외가 발생하면 응용프로그램 실행이 중단됩니다. 반면에 오버플로우를 허용하고 계산되도록 하고 싶다면, 오버플로우 연산자 “&+”, “&-“, “&*”을 사용합니다.

오버플로우가 발생하지 않을 경우에는 실행시 각각의 연산자에 “&”을 추가한 것과 동일합니다. 즉,  덧셈, 뺄셈, 곱셈은 일반적인 연산자의 동작과 동일하지만 나눗셈, 나머지로 나누는 수는 0이면 연산결과가 0이 됩니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var x: UInt8 = 100
x &+ 1 // 101
x &+ 2 // 102
x &* 2 // 200
[/code]

[예제 2-44] 오버플로우 연산자 예제[/vc_column_text][vc_column_text]

형확인/형캐스트/형변환

변수에 대한 형확인은 “is”를 사용합니다. 오른쪽 항목 형의 확인을 하게 됩니다.

var msg : NSString = “abc” // NSString 형으로 문자열 msg선언

msg is NSMutableString // true

Swift언어에서는 구조체나 열거형에도 Any형을 상속하기 때문에 Any형으로 선언한 변수는 구조체나 Enum형도 할당할 수 있습니다. 즉 Any형 변수에 저장된 값 형을 체크하기 위해서 is연산자를 사용하는 것도 가능합니다.

var c : [Any] = [CGSize(width:10, height:10) “z”, 1]

c[0] is CGSize // true

c[0] is String // false

단, 컴파일 할 때 판정가능한 확인은 컴파일시 경고합니다. 즉 is 연산자를 사용한다는 것은 런타임 판정만한다는 것입니다.

그리고 하위 형으로 변환할 경우에는 “as!” 또는 “as?”를 사용합니다. 캐스트에 의해 하위형 고유의 메소드와 속성을 사용할 수 있게 됩니다. “as!”는 변수가 확실한 캐스팅이 가능할 때 사용하지만 실행시 캐스트가 실패하면 오류가 발생합니다.

“as?” 형검사 및 캐스트를 동시에 합니다. “as?”는 Optional구조를 사용하여 형변환을 실패하면 값은 nil이 됩니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
for product in array {
let x = product as? Int // 형변환을 성공하면 해당 값이 나오고 실패하면 nil
if x != nil {
var y = x! + 7
}
}
[/code]

[예제 2-45] 형확인 및 형변환 동시 실행 예제[/vc_column_text][vc_column_text]위 예제를 좀더 간단하게 구현할 수 있는데 이것에 대해서는 나중에 Oprional 바인딩에서 다시 설명할 예정입니다. 그리고 확실한 캐스트가 가능한 경우 “as”에 의한 형 캐스트를 이용할 수 있지만, “as!”, “as?”도 똑같이 사용 가능합니다.[/vc_column_text][vc_custom_heading text=”(4) 우선순위/결합 규칙” use_theme_fonts=”yes”][vc_row_inner][vc_column_inner width=”1/2″][vc_column_text]Swift언어에서 이항 연산자의 우선순위와 결합 규칙은 Objective-C언어와는 약간 다르기 때문에 기억하기 바랍니다.

우선순위는 0부터 255까지의 정수로 표현된 숫자가 클수록 우선순위가 높다는 것을 의미하고 단항 연산자는 이항 연산자보다 우선순위가 높습니다.

결합규칙은 오른쪽 결합, 왼쪽 결합, 무결합이 있습니다. 오른쪽 결합 연산자는 우선순위가 같은 연산자 OPERATOR 가 “x OPERATOR y OPETATOR z”와 연속되는 경우 “x OPERATOR (y OPERATOR z)”, 오른쪽부터 순서대로 해석합니다. 왼쪽 결합 연산자는 우선순위가 같은 연산자 OPERATOR가 “x OPERATOR y OPERATOR z”의 경우와 “x OPERATOR y) OPERATOR z”는 왼쪽에서 오른쪽으로 해석되는 것입니다. 그리고 무결합은 “ x OPERATOR y OPERATOR z”와 같이 동일한 우선순위 연산자 OPERATOR를 연속해서 오류가 됩니다.[/vc_column_text][/vc_column_inner][vc_column_inner width=”1/2″][vc_single_image image=”846″ img_size=”full” alignment=”center”][/vc_column_inner][/vc_row_inner][vc_column_text]즉, Objective-C연산자의 우선순위와는 다소 차이점이 있다는 것을 이해하고 이런 오류를 범하기 전에 연산순서를 “(  )”(괄호)를 명시적으로 넣어 구분하는 방법을 추천합니다.[/vc_column_text][vc_custom_heading text=”(5) 사용자정의 연산자/연산자 오버로딩” use_theme_fonts=”yes”][vc_column_text]Swift언어는 클래스나 구조체에 대한 새로운 연산자를 정의하고 구현이 가능하고 기존의 연산자 실행형태를 변경할 수 있습니다. 도입 가능한 연산자는 단항 연산자와 이항 연산자가 있습니다.

연산자 함수

이항 연산자를 도입하려면그 연산자명의 함수를 정의해야 합니다. 함수 인수는 연산자의 왼쪽부분과 오른쪽 부분을 의미합니다. Left와right로 지정합니다.

예로 연산자 “*”에 대해 “문자열 * 정수” 연산을 처리하는 함수를 정의한다고 생각하고 구현한 부분을 살펴봅시다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
func * (left: String, right: Int) -> String {
var msg = ""
for _ in 0..<right { msg += left } return msg } let msg = "가나다" * 3 // 결과: 가나다가나다가나다 [code] [예제 2-46] 이항 연산자 정의[/vc_column_text][vc_column_text]단항 연산자는 전위(prefix)와 후위(postfix)가 있고 연산자 함수를 정의할 떄 prefix와 postfix를 지정해야 합니다. [code lang="swift"] postfix func ++ (left: Double) -> Double {
return left + 2.0
}

10.123++ // 결과: 12.123
[/code]

[예제 2-47] 단항 연산자 정의[/vc_column_text][vc_column_text]복합 대입 연산자(“+=”, “-=”)의 경우, 이항 연산자 형태로 연산자 함수를 정의합니다. 단, 첫번째 인수 left값이 변경되기 때문에 첫번째 인수에 inout을 지정해야 합니다.

연산자 함수의 정의에서 기존 연산자 실행을 변경하는 것이 가능하지만, 확인하기 어려운 버그로 인해 프로그램이 망가질 수 있기 때문에 최대한 사용을 안하는 것을 추천합니다.

 

사용자정의 연산자

Swift언어에서는 새로운 연산자를 추가할 수 있습니다. 연산자에 사용할 수 있는 문자는 “/”, “=”, “-“, “+”, “*”, “%”, “<”, “>”, “!”, “&”, “|”, “^”, “~”이외에 “×”, “÷”, “←”, “↑”, “↔”등 2천개 정도가 있습니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]</pre>

postfix operator ** {}
postfix func ** (left: Double) -> Double {
return left * left
}
let x = 3.0
x** // 결과: 9
<pre>[/code]

[예제 2-48] 사용자정의 연산자 정의[/vc_column_text][vc_column_text]Postfix 후위로 operator전에 처리하는 경우로 전위 연산자로 처리할 경우 prefix에서 infix를 사용합니다.

infix operator 연산자 {associativity 결합규칙 precedence 우순순위}

예로 부동소수점끼리 뺄셈/덧셈 연산자 “∓”를 정의 하는 예제를 만들어보겠습니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]

infix operator ∓ { associativity left precedence 140 }

func ∓ (left: Double, right: Double) -&gt; (Double, Double) {
return (left – right, left + right)
}
2.0 ∓ 7.0

[/code]

[예제 2-49] 새로운 연산자 정의[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_separator][vc_btn title=”목차로 가기” color=”orange” align=”center” link=”url:%2Fswift-2-korean-book%2F|title:%EB%AA%A9%EC%B0%A8|”][/vc_column][/vc_row]

Facebook Comments

카테고리:   Swift Books

댓글

죄송하지만 댓글은 닫혀 있습니다.