brunch

You can make anything
by writing

C.S.Lewis

by MJ Apr 01. 2017

2. 변수, 상수 & 기본적인 형들

Swift 3.x Programming

[이 글은 필자의 블로그 Swifter.kr과 브런치에 같이 올리는 강좌입니다.]


변수와 상수는 프로그램에 나오는 값을 기억하기 위한 그릇이다. 모든 변수 및 상수는 형을 가지고 있으며, 형은 그것들에게 대입할 수 있는 값의 종류를 나타낸다. 변수 및 상수는 일정한 범위 내 프로그램에서 참조가 가능하고 필요에 따라 값을 다시 사용할 수 있다. 이번 내용에서는 Swift 3.0 언어의 변수 및 상수를 처리하는 방법 기본적인 형들을 정리해본다.


1. 변수, 상수 및 형에 의한 값 관리

변수 및 상수 값의 저장에 사용한다. 변수는 설정된 값을 변경할 수 있고 상수는 설정된 값을 변경할 수 없다. 프로그램의 규모가 커질수록 값 관리는 복잡해지고, 변수 및 상수의 구별은 고려하지만 변경은 최소화한다.

형은 변수와 상수에 들어있는 값의 종류를 알 수 있다. Swift 언어는 숫자나 문자 열등의 일반적인 프로그램에 나오는 일반적인 값을 나타내는 형은 내장되어 있다. Swift언어의 주요 내장된 형은 Bool형, 숫자형은 String, Array <Element> 형, Dictionary <Key, Value> 형, 범위형인 Optional <Wrapped> 형, Any형에 대해서 이제 알아볼 것이다. 또한 형은 표준 라이브러리에서 제공하는 것 이외에 독자적인 형도 정의할 수 있다.


2. 변수와 상수

변수는 값을 저장하기 위한 그릇에 이름과 형을 가지고 있다. 이름은 변 수명이라고 하며, 변수명은 프로그램에서 변수에 접근하는 데 사용한다. 형은 변수가 가지는 값의 종류에서 변수에 어떤 값을 대입할 수 있는지를 보여준다. 변수는 형이 일치하는 값이면 몇 번이나 다시 할당할 수 있다. 상수는 값을 가진 그릇으로 변수와 비슷하지만 값이 다시 할당할 수 없다. Swift 언어는 한번 대입한 값을 변경할 필요가 있는 경우 변수를 사용하여 변경할 필요가 없으면 상수를 사용한다. 상수를 사용하면 값 변경을 고려할 필요 없고, 변경이 예상되지 않는 값을 업데이터 하는 오류를 범하지 않을 수 있다.


선언 방법

변수는 var, 상수는 let이란 키워드를 사용하여 아래와 같이 선언한다.


var 변수명: 형 // 변수 선언

let 상수명: 형 // 상수 선언


아래 예제에서는 첫 번째 줄은 변수명 a라는 Int형 변수를 선언하고 두 번째 줄은 정수명 b는 Int형 정수를 선언한다.


var a: Int // Int형 변수

var b: Int // Int형 상수


변수 및 상수의 선언 형태는 var, let의 선언 차이만 있다. 문법은 변수가 사용할 수 있는 것들이 많고 정수도 사용할 수 있다. 변수 및 상수 선언 시 형명을 나타내는 : Int형태는 형 주석(Type annotation)이라고 하며 주석은 의미를 가지는 변수 및 상수형을 명시적으로 결정하는 역할을 한다.


형 추론

변수 및 상수는 선언과 동시에 값을 할당할 수 있다. 아래 에는 Int형 정수 a를 선언함과 동시에 100을 대입하고 있다.


let a: Int = 100


100은 Int형이기 때문에 형주석이 없어도 상수 a형이 Int형이라고 추론할 수 있다. 이처럼 대입되는 값에서 형을 유추할 수 있는 경우 형주석을 생략할 수 있다. 형주석을 생략하면 변수 및 상수 형은 대입되는 값에 따라 달라진다. 에로 선언할 때 Int형값을 대입하면 Int형으로 인식되고 String형값을 대입하면 String형이 된다.


let a = 100 // Int형

let b = "대한민국" // String형


위와 같이 프로그램에서 암시적으로 형을 결정하는 구조를 형 추론이라고 말한다. 일반적으로 형 추론을 사용한다면 형주석을 생략하고 형주석이 없으면 변수 및 상수 형을 결정할 수 없는 경우에만 형주석을 추가한다.


형 확인방법

형주석과 형 추론에 의해 결정되는 변수 및 상수형을 확인하려면 type(of:) 함수를 이용한다. type(of:) 함수는 실행할 때 형을 리턴하는 함수로 다음과 같이 사용한다.


type(of: 변수명 또는 상수명)


100을 통해 형 추론된 상수 a의 형을 확인하려면 다음과 같이 작성한다. type(of: a)의 결과는 Int.Type이라고 나온다.


let a = 100

type(of: a) // Int.Type


팁으로 Xcode로 코딩할 때 변수와 상수형을 표시하는 QuickHelp라는 기능이 있는데 이를 활용해보자. 형을 알고 싶은 변수나 상수에 커서를 가져가고 Xcode 메뉴에서 [Help] - [Quick Help for Selected Item] (Control + Command +? 키)를 선택하면 아래 화면처럼 변수 및 상수형 정보가 팝업으로 표시된다. 또는 Xcode 메뉴에서 [View] - [Utilities] - [Show Quick Help Inspector] (Control + Command + 2 키)를 누르면 화면 오른쪽에 상세화면으로 형 상태를 보여준다.

Swift 언어에서 변수나 상수명은 알파벳 및 숫자뿐만 아니라, 한글 및 중국어, 이모티콘도 사용이 가능하다. 그러나 실제로 알파벳과 숫자만 사용하는 것이 실무 개발의 현실이다. 또한 변수 및 상수명은 이름과 형을 가질 필요가 있다. 즉, 형주석을 사용하거나 값을 할당하여 해당 형을 결정해야 한다.

예로 다음과 같이 형주 석도 값도 대입하지 않는 코드는 형이 결정하지 않았기 때문에 컴파일 오류가 발생한다.


let a // 컴파일 오류


할당방법

변수와 상수에 값을 할당하려면 = 연산 자을 기준으로 좌측에 변수 및 상수명을 입력하고 우측에 해당 값을 입력한다.


변수명 또는 상수명 = 대입되는 값


아래 예는 Int형 변수 a를 선언하고 10 값을 대입하는 것을 보여준다.


var a: Inta = 10


Swift 언어에서는 변수 및 상수를 안전하게 이용하기 위해서 할당에 관련 몇 가지 규정이 있는데 이에 대한 규정을 컴파일러에서 체크하기 때문에 규정을 어긴 프로그램을 실행할 수 없다.

변수 및 상수에 할당할 수 있는 값은 변수와 상수 형에 일치하고 있는 것만 가능하다. 예로 형주석에 지정된 형과 대입하는 값형이 일치하지 않는 경우 컴파일 오류가 발생한다. 아래 예는 Int형 형주석이 추가된 상수 a에 Int형값 100을 대입하여 오류가 발생하지 않지만 다음으로 Int형 주석이 추가된 상수 b에 String값 "대한민국"을 대입하여 컴파일 오류가 발생한다.


let a: Int = 100 // 문제없음

let b: Int = "대한민국" // 오류


대입에 의한 형이 정해진 경우도 동일하다. 선언할 때 Int형 값을 할당한 변수에 String값을 선언했기 때문에 컴파일 오류가 발생한다. 변수 및 상수는 다른 변수와 상수값을 할당할 수 있다. 이 경우 대입은 원래 변수와 상수에 대입하는 변수 및 상수형이 일치해야 한다.


let a = 1

var b = a //1


+ 연산자 등의 연산 결과나 함수 호출 결과 등 처리 결괏값을 리턴하는 형태를 표현식이라고 한다. 식이 리턴 값 형이 변수나 상수형과 일치하는 경우, 변수 및 상수에 할당한다. 아래 예는 Int형과 Int형의 연산 결과인 Int형값을 Int형 정수에 대입은 표현식을 보여준다.


let a: Int = 3 + 5 //8


지금까지의 예로 나온 3이나 1 및 "대한민국"등의 값을 프로그램에 직접 표기하는 형을 리터럴이라고 하며 Swift언어에서는 변수 및 상수값이 존재하지 않는 것을 nil이라는 리터럴로 표현하지만 대부분의 형은 nil리터 털을 허용하지 않는다. 아래 예는 Int형 변수에 nil리터럴을 할당하고 있지만 Int형에 nil리터럴을 할당하면 오류가 발생한다.

변수와 상수가 처음 하는 것은 초기화가 있다. 초기화하지 않는 변수 및 상수값을 가지고 있지 않기 때문에 그대로 값을 사용할 수 없습니다. 따라서 컴파일러는 초기화되지 않는 변수 및 상수 사용을 감지하고 컴파일 오류가 발생한다. 아래 예는 Int형 변수 a가 초기화되기 전에 이용되어 오류가 발생하는 것을 보여준다.


var a: Int

print(a) // a변수가 초기화되지 않았기 때문에 오류 발생


초기화되지 않는 변수 및 상수의 사용은 컴파일 오류가 발생하기 때문에 컴파일이 가능한 프로그램은 초기화되지 않은 변수 및 상수에는 접근할 수 없다. 따라서 Swift언어 기반 프로그래밍에서는 초기화되지 않는 상태의 변수 및 상수에 대한 접근은 안된다는 것을 명심하자.

또한 변수는 몇 번이라도 재할당이 가능하지만, 상수는 재할당이 금지되어 있기 때문에 다시 할당하는 경우 컴파일 오류가 발생한다.


var a = 100

a = 200 // a는 변수라서 다시 할당 가능

let b = 100

b = 200 // b는 상수라서 다시 할당 불가 , 오류 발생


상수는 다시 할당할 수없기 때문에, 반드시 상수의 선언과 동시에 값을 할당할 수 없다. 예로 상수 선언만 하는 경우에도 대입이 한 반밖에 하지 않는 것을 고려해서 작업한다면 오류가 발생하지 않는다.


let a: Int

let statement = true

if statement {    

    a = 100

} else {   

    b = 200

}


실제로 대입은 한 번밖에 되지 않는 코드 이지마 컴파일러가 이를 보장하지 못하면 컴파일 오류가 발생한다. 예로 정수 index에 1이 있는 상태에서 a = index가 한 번만 실행되지만 컴파일러는 상수 a에 한 번만 대입된다는 것을 보장하기 어렵기 때문에 컴파일 오류가 발생한다.


let a: Int

for index in [1] {   

    a = index // 컴파일 오류

}



3. 범위

범위는 변수, 상수, 함수, 형 이름의 범위를 나타내는 것을 말한다. 범위는 그 범위에 따라 전역, 로컬 범위로 나뉜다. 동일한 범위 내에 동일한 이름은 여러 개가 존재할 수 없으며, 변수, 상수, 함수형의 종류가 다르더라도 이름을 고유해야 한다.

또한 여기서는 변수 및 상수를 에로 범위를 설명하지만 함수 및 형의 범위도 동일하다.

로컬 범위는 함수나 구문에 의해 정의되는 범위를 말한다. 로컬 범위는 선언된 변수나 상수는 함수나 구문이 있는 실행문 내부에서만 유효한 범위이며 외부에서는 참조할 수 없다. 아래 예제는 함수 examFunction()에 상수 a를 선언하고 있다. examFunction() 함수 안이 범위이기 때문에 상수 a를 볼 수 있지만 함수 외부는 포함되지 않아 a를 참조할 수 없다.


fun examFunction {    

     let a = "x"    

     print(a) // 문제없음

}

print(a) // 컴파일 오류

examFunction()


로컬 범위에서 선언된 변수나 상수는 제한된 범위에서만 참조되지 않기 때문에 의도하지 않은 변경이 일어나기 어렵다.

전역 범위는 모든 함수의 형 선언에도 포함되지 않는 범위를 말한다. 전역 범위에 선언된 변수와 상수는 어디서나 볼 수 있다. 아래 예는 전역 상수 a를 정의하는 함수 examFunction() 내부와 외부에서 참조한다.


let a = "출력"

func examFunction() {    

      print(a) // 문제없음

}

print(a) // 문제없음

examFunction()


전역 범위에 선언된 변수 및 상수는 어디에서나 동일한 이름으로 참조할 수 있기 때문에 의도치 않는 변경이 있을 수 있어 되도록 전역 변수나 상수명을 바로 알 수 있는 이름으로 짓도록 하자.


4. Bool형

이번에는 참과 거짓을 따질 때 사용하는 Bool형에 대해 알아보자. 어떤 하나의 명제가 참인지 거짓인지를 나타내는 값을 Bool형의 값이라고 한다.


Bool형 상수값

참 거짓 값을 나타내는 리터럴을 Bool형 상수값에 true와 false로 나타낸다. 참 거짓 값의 대입 부분의 변수와 상수형이 형주석에 의해 명시되어 있지 않으면 Bool형이 된다.


let a = true // Bool형

let b = false // Bool형


논리 연산

논리는 참 거짓 값에 대한 연산을 말하며, Bool형은 부정, 논리곱, 논리합이 있으며, Swift연산자의 배치위치로 전치 연산자와 사칙 연산자, 후치 연산자로 구분하며 전치 연산자는 -a, 변수 및 상수 사이에 들어가는 사칙 연산자 a+b와 같은 형태가 있고 후치 연산자는 a! 와 같은 변수 및 상수 뒤에 배치한다.


부정

부정은 참 거짓 값의 진위를 반대로 처리하는 논리를 말한다. Bool형의 부정으로 처리하려면 전치 연산자!로 사용한다. 아래 예제에서는 정수 a에 true를 대입하여 상수 b에 상수 a의 부정이 다를 정의해본다.


let a = true //true

let b =! a // false


논리곱

논리곱으로 주어진 여러 가지 참 거짓 값이 모두 참이면 참이 되는 논리이다. 2개의 Bool형값의 논리적 요구하려면, && 연산자를 사용한다. && 연산자는 삽입하는 사칙연산 자이며 양쪽의 Bool형값을 얻는다. 예로 2개의 Bool형 값 조합이 교집합으로 정리하여 각 상수 a, b, c, d에 대입한다.


let a = false && false // false

let b = true && false // false

let c = false && true // false

let d = true && true // true


논리합

논리합은 주어진 여러 가지 참 거짓 값 중 적어도 한 개가 참이어야 하는 논리이다. 2개의 Bool형값의 논리합은 || 연산자를 사용한다. 아래 예는 2개의 Bool형 값 조합의 논리합을 정리하면 각 상수 a, b, c, d에 대입한다.


let a = true || false // true

let b = false || true // true

let c = true || true // true

let d = false || false // false



5. 수치형

수치를 나타내는 수치형에 대해서 정리해본다. 지금까지의 설명에 정수를 나타내는 Int형을 소개했는데 Swift 언어에서는 Int형 이외에도 다양한 수치 자료형이 있다.


숫자 리터럴

수치를 나타내는 리터럴을 숫자 리터럴이라고 하며 정수 리터럴, 부동소수점 리터럴 등이 있다. 100과 같은 정수 상수값은 정수 값을 나타내고 3.14등의 부동소수점 리터럴 값을 나타낸다. 정수 리터럴은 나중에 설명하는 Int형이나 Int64형 등의 정수에 대입할 수 있다. 대입시 변수나 상수형이 명시되어 있지 않다면 정수 리터럴은 기본적인 Int형이다.

또한 부동소수점 리터럴도 기본형을 가지고 있고 할당 대상 변수 및 상수의 형아 형주석에 명시되어 있지 않다면  Double형으로 인식된다.


let a = 3.0 //Double 앱


수치형 종류

Swift언어의 숫자는 크게 분류하면 정수형과 부동소수점 2가지로 나눌 수 있다.


정수형은 정수를 나타내는 형이다. 정수형은 유지할 수 있는 값의 비트수등에 따라 다양한 형으로 분류된다. 대표적인 정수는 Int형이다. Int형 비트수는 32비트 플랫폼에서 32비트, 64비트 플랫폼에서 64비트로 나뉜다. 고정 비스트수의 정수는 Int8, Int16, Int32, Int64이 있고, 각각 8비트, 16비트, 32비트, 64비트이다. 각 형의 최소값과 최대값은 아래와 같다.

Int8: -128 (최소값) ~ 127 (최대값)

Int16: -32,768 ~ 32,767

Int32: -2,147,483,648 ~ 2,147,483,647

Int64: -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

정수의 최소값과 최대값은 정적인 속성 min, max를 통해 접근할 수 있다. 사용하는 방법은 형명에 .(점)을 붙이고 속성을 추가해서 사용할 수 있다.


let a = Int16.min

let b = Int16.max


부동소수점은 소수를 나타내는 숫자를 말하며, Float형과 Double형이 있고 각각 32비트, 64비트의 고정 비트수를 가진다. 부동소수점은 최소값, 최대값을 나타내는 속성은 없고, Float형은 약 10에 38제곱의 값을 나타낼 수 있고 Double형은 약 10에 308제곱값을 나타낸다. 부동 소수점형은 비트숭에 따라 표현할 수 있는 값의 범위뿐만 아니라, 값의 정밀도도 다른 것에 주의하자. 64비트 Doubel형은 최소 15자리의 정밀도를 가지며, Float형은 최소 6자리의 정밀도를 가진다.


부동소수점 형은 정적인 속성으로 NaN(Not a Number)을 나타내는 nan도 있다. 이는 연산할 때 부정한 값이 전달되어 버린 경우 연산을 할 수 없다는 것을 나타낸다. 부정 소수점형에 대한 잘못된 연산을 하게 되면 값은 nan이 된다. 이때 값이 NaN인지를 체크하는 isNaN속성을 true로 리턴한다.


let a: Duuble = 0.0 / 0.0

a.isNaN // 참

let b: Double = Double.nan

b.isNaN // 참



수치형끼리의 상호변환

Swift언어는 정수형끼리나 부동 소수점끼리라고 해도 형이 다르면 할당할 수 없다. 아래 예처럼 Int64형 상수 b에 Int형 상수 a의 값을 대입하거나 Double형 정수 d에 Float형 상수 c에 값을 할당할 수 없다.


let a: Int = 100

let b: Int64 = a // 오류

let c: Float = 1.0

let d: Double = c // 오류


숫자를 다른 숫자형으로 변환하라면 이니셜 라이저를 사용해야 한다. 이니셜 라이저는 자료형 값을 만들고 초기화하는 것으로 형명()이라는 형식으로 실행한다. 수치형은 다른 수치형값에서 자신의 형값을 생성하는 이니셜 라이저가 준비되어 있기 때문에 변환이 가능하다. 아래 예는 대입할 수 없는 값을 이니셜 라이저를 사용하여 할당할 수 있는 자료형 값으로 변환한다.


let a: Int = 100

let b: Int64 = Int64(a) // 문제없음

let c: Float = 1.0

let d: Double = Double(c) // 문제없음


이니셜 라이저와 함수 ()(괄호)에 입력한 값이 되는 인자를 열거할 수 있고 생성하려는 형보다 정확한 형으로 초기화하면 생성된 형의 정밀도에 맞추기 위해 반올림한다.


let c: Float = 1.99

let d: Int = Int(c) // 1

let e: Double = 1.23456789

let f: Float = Float(e) // 1.234568


수치형 작업

연산자와 수학 함수를 사용한 수치 작업방법을 정리해본다. 우선 비교 연산자는 숫자끼리의 대소 관계를 보여준다.

true값을 리턴해주는 조건

== : 왼쪽과 오른쪽이 일치할 때

!= : 좌측과 우측이 일치하지 않는 경우

> : 좌측이 우측보다 클 때

>= : 좌측이 우측보다 크거나 같을 때

< : 우측이 좌측보다 클 때

<= : 우측이 좌측보다 크거나 같을 때

Swift언어의 비교 연산자는 비교대상이 되는 두 숫자형이 일치하는 경우에만 사용할 수 있다. 형이 일치하지 않으면 컴파일 오류가 발생한다. 다른 형의 값을 비교하려면 명시적 변환을 하여 일치시킨 후 처리해야 한다.


let a: Int = 100

let b: Int64 = 100

a == b // 컴파일 오류

a == Int(b) // 문제없음


이렇게 처리하는 것이 번거롭지만 자동변환을 허용하면 예상하지 못한 오류가 발생할 수 있기 때문에 형 안전성을 고려한 것이다.


산술 연산자는 아래와 같은 형태로 제공한다.


// 덧셈

1 + 1 //2

// 빼기

3 - 2 //1

//곱셈

2 * 3 //6

//나누기

6 / 2 //3

// 나머지

9 % 2 //1


위와 같은 산술 연산자도 두 숫자형이 일치해야 사용 가능하다.

수치형 변수에 대해서는 이런 연산자와 대입 연산자 =를 합친 복합 대입 연산자를 사용할 수 있다. 복합 대입 연산자는 산술 및 할당을 동시에 하고 좌측에 산술 결과를 대입한다.


// 덧셈

var a = 1

a += 5 //6

// 빼기

var b = 3

b -= 3 //0

// 곱셈

var c = 2

c *= 3 //6

// 나누기

var d = 6

d /= 3 //2

// 나머지

var e = 5

e %= 2 //1


Foundation 표준 라이브러리에서는 삼각함수의 고급 함수가 있는데 sin(_:) 삼각함수 및 log(_:) 로그함수 및 파이값은 Float형의 정적인 속성인 pi가 있다.


import Foundation

sin(Float.pi /2.0) //1



6. String형

이번에는 알파벳이나 한글과 같은 문자열을 나타내는 String형에 대해 알아보자.


문자열 리터럴

문자열을 나타내는 리터럴을 문자열 리터럴이라고 하며 "abcd"나 "대한민국"과 같이 "(큰따옴표)로 문자열을 둘러싸면 문자열 리터럴로 해석한다. 문자열 리터럴에는 문자열을 나타내는 String형과 문자를 나타내는 Character 형이 있다. 문자열 리터럴의 기본형은 String형이다.


let a = "문자열 입력" //string형


문자열 리터럴을 표기할 때 한 줄씩 끊어서 넣고 싶다거나 할 때 \(백 슬레시)를 넣고 특수문자를 표현할 수 있는데 이것을 이스케이프 시퀀스라고 한다.

\n :  줄 바꿈

\r : 캐리지 리턴

\" : 큰 따옴표

\' : 작은따옴표

\\ : 백 슬래시

\0 : null문자

또한, \()을 사용하면 값을 문자열 리터럴에 포함하여 사용할 수 있다. 이 방법은 평가결과를 문자열 리터럴에 포함하여 처리할 수 있다.


let result = 3 + 4

let s = "결과: \(result)" //결과: 7


물론 숫자 결괏값만 가능한 것이 아니라, String형 값도 삽입이 가능하다.


String형 개별 문자를 표현하기

String형의 개별 문자는 Character형으로 표시되고 Character형 묶음은 String.CharacterView형으로 표시된다. 이 형은 String형에 중첩하여 정의되어 있는지를 나타낸다.

Character형은 "a"와 같은 단일 문자를 말한다. Character형 값은 String형과 동일하게 문자열 리터럴로 표현할 수 있다. 문자열 리터럴의 기본 형은 String형으로 되어 있기 때문에 문자열 리터럴에서 Character형 변수 및 상수를 만들려면 형주석을 붙이는 방법이 있다.


let str = "a" //String형

let cha: Character = "a" //Character형


String.CharacterView형은 Character형의 컬렉션을 나타내는 형으로 컬렉션은 데이터 집합을 함께 저장하는 데이터 구조에서 요소 열거 및 요수수를 계산하는 기능이 있다. String.CharacterView형은 일반적으로 별도로 만드는 것이 아니라 String형의 characters속성에 이미 존재하는 것을 사용한다. 만약 String.CharacterView형에서 Character형 요소를 제거하려면 서브 스크립트라는 기능을 이용한다. 서브 스크립트는 컬렉션에 인덱스를 통해 요소를 얻고 변경하는 기능이며 컬렉션에 [] 대괄호로 묶은 인덱스를 지정하여 컬렉션 인덱스라는 형으로 사용한다. startIndex속성, endIndex속성, index(_: offsetBy:) 메서드를 사용한다.


let str = "대한민국"

let cha = str.characters // String.CharacterView형

let cha1 = cha [cha.startIndex] //대


endIndex속성은 종료 인덱스를 말하는데 마지막 문자의 인덱스가 아니라 그다음 인덱스라는 것을 기억하자. 즉, endIndex속성 값을 그대로 지정하면 런타임 오류가 발생하기 때문에 주의하자.

마지막 문자 인덱스와 n번째 문자의 인덱스를 얻으려면 index(_: offsetBy:) 메서드를 사용하여 startIndex속성 및 endIndex속성이 리턴하는 값이다. index(_: offsetBy:) 메서드는 컬렉션. index(원본 인덱스, offsetBy: 지정 숫자)라는 형식이다.


let str = "대한민국"

let cha = str.characters // String.CharacterView형

cha.count //4

for c1 in cha {

    print(c1)

}


숫자 값의 상호 변환

String형 및 수치형 상호변환에는 이니셜 라이저를 사용한다.


let a = 100

let b = String(a) // "100"


String형 값을 Int형으로 변환하는 경우 Int형 이니셜 라이저를 사용한다. 문자열은 반드시 숫자형으로 되어 있다고 할 수 없기 때문에 String형에서 수치형으로의 변환은 실패할 수 있다. 따라서 Int형 이니셜 라이저는 nil이 될 수 있는 Optional <Int> 형 값을 리턴한다. 수치로 변환할 수 없는 문자열을 변환하면 결과는 nil이 된다.


let a = "100"

let a1 = Int(a) // 100

let b = "대한민국"

let b1 = Int(b) // nil


String 및 Character형 조작하기

Swift 언어는 기본적으로 문자열은 String형으로 취급하고 문자는 Character형으로 취급한다.

비교는 ==연산자를 사용한다. 비교 시 주의해야 할 점은 암시적 변환은 존재하지 않기 때문에 어느 쪽이든 한쪽 형을 맞춰야 한다.


let str: String = "A"

let cha: Character = "A"

str == cha // 오류

str == String(cha) // 문제없음


다음 String형끼리의 결헙에 +연산자를 사용할 수 있다. 그 외 append(_:) 메서드를 이용하여 같은 형끼리 결합할 수 있다.

단, 표준 라이브러리는 대소문자를 구별하지 않고 비교하거나 문자열 탐색 등의 기능은 준비되어 있지 않기 때문에 Foundation 코어 라이브러리를 사용해야 한다.


import Foundation 


let o1 = String.CompareOptions.caseInsensitive

let o2 = "대한민국". compare("대한민국", options: o1)

o2 == ComparisonResult.orderedSame // 참

"대한민국". range(of: "대한")


두문자 열 간의 순서 비교 부분에서는 compare(_: option:) 메서드로 2개의 문자열 사이 순서를 확인한다. option에. caseInsensitive을 선언하여 대소문자를 구별하지 않고 값을 얻고 있다. 문자열 검색 부분에서는 range(of:) 메서드에서 "대한민국" 문자열에 "대한"이 어떤 범위에 포함되어 있는지를 확인해준다.


7. Array <Element> 형

배열을 나타내는 Array <Element> 형에 대해 알아보자. 배열은 순서를 가진 컬렉션으로 Element에 구체적인 형을 선언하여 Array <String> 형이나 Array <Int> 형 형태로 구현한다. 이때 <> 내에 플레이스 홀더형을 가진 것을 제네릭형이라고 말한다. 또한 Array <Element> 형은 [Element]라는 구문 형태가 준비되어 있다.


배열 리터럴

Array <Element> 형을 [1, 2, 3, 4, 5]와 같은 배열 리터럴을 사용하여 표현할 수 있다. 배열 상수값은 [] 안에 쉼표(,)로 구분하여 열거한다.


let a = [1, 2, 3]


배열 리터럴이 포함 요소형에서 Array <Element> 형의 플레이스 홀더형인 Element를 추론한다. 예로 배열 리터럴은 String요소만 가지고 있는 경우 [String] 형으로 추론한다.

단, 빈 배열 리터럴의 경우, 요소가 존재하지 않는 경우 추론을 할 수 없다. 따라서 빈 배열 리터럴 형주석을 추가하여 형을 명시하는 것이 좋다.

Element형의 값을 요소로 사용할 수 있다. 예로 [Int] 형은 Int형 값을 사용할 수 있고 [String] 형은 String형값을 사용할 수 있다.


let i = [1, 2, 3, 4, 5] // [Int] 형

let s = ["a", "b", "c", "d"] // [String] 형


Element형에는 어떤 형이라도 적용할 수 있다. 예로, Element형에 [Int] 형을 적용하여 Int형 배열의 벼슬을 나타내는 [Int] 형을 나타낼 수 있다. [[Int]]형처럼 배열을 요소로 가지는 배열을 2차원 배열이라고 한다.


let ia = [[1,2], [3,4]] //[[Int]]형


요소형은 다른 형값을 포함하면 컴파일 오류가 발생한다. 예로, [Int] 형에 String값 "a"를 포함시키는 경우 오류가 발생한다.


let a: [Int] = [ 1, 2, "a"] //컴파일 오류


Array <Element> 형 조작하기

Array <Element> 형 요소에 접근하려면 서브 스크립트를 사용한다. 서브 스크립트의 인수는 요소 인덱스를 나타내는 Int형 값을 사용한다. 첫 번째 요소 인덱스는 0에서 1, 2 순서대로 이어진다. 인덱스가 범위에서 벗어나거나 하면 오류가 발생한다.


let s = ["대한", "민국", "만세"] // 인덱스 0, 1, 2

let s1 = s [0] // "대한"

let s2 = s [1] // "민국"

let s3 = s [2] // "만세"

let s4 = s [3] // 인덱스 3은 범위를 벗어났기 때문에 오류남


Array <Element> 형 값에 대한 요소의 추가, 변경, 결합, 삭제를 할 수 있는데 기존 요소를 변경하려면 변경 시 요소 인덱스를 서브 스크립트의 인자로 대입 연산자 =를 사용하여 새 값을 설정한다.


var s = ["대한", "민국", "만세"]

s [1] = "국민"

s // ["대한", "국민", "만세"]


요소 끝에 추가하려면 append(_:) 메서드를 사용한다. Array <Element> 형의 append(_:) 메서드는 Element형값을 인수로 얻는다. 예로  [Int] 형 변수 i에 Int형 5를 추가한다.


var i = [1, 2, 3, 4]

i.append(5) // [1, 2, 3, 4, 5]


임의의 위치에 요소를 추가하려면 insert(_:at:) 메서드를 사용한다. insert(_:at:) 메서드는 추가 요소로 추가하는 위치의 인덱스를 인수로 얻는다.


var i = [1, 2, 4]

i.insert(3, at: 2) // [1, 2, 3, 4]


+연산자 형이 일치하는 Array <Element> 형을 결합할 수 있다.


let i1 = [1, 2]

let i2 = [3, 4]

let i = i1 + i2 // [1, 2, 3, 4]


요소 제거는 임의의 인덱스 요소를 삭제하는 remove(at:) 메서드와 마지막 요소를 삭제하는 removeLast() 메서드, 모든 요소를 삭제하는 removeAll() 메서드가 있다.


var i = [1, 2, 3, 4, 5]

i.remove(at: 3)

i // [1, 2, 3, 5]

i.removeLast()

i // [1, 2, 3]

i.removeAll()

i // []



8. Dictionary <Key, Value> 형

사전을 나타내는 Dictionary <Key, Value> 형을 알아보자. 사전은 키와 값을 쌍으로 가진 컬렉션이며 키를 원래 값에 접근하기 위한 용도로 사용된다. 키와 값의 쌍 사이에 순서는 상관없다. 키는 접근 대상의 구분을 사용되기 때문에 고유하며 값은 중복되어도 문제가 없다.

Array <Element> 형과 마찬가지로 Dictionary <Key, Value> 형의 Key와  Value플레이스 홀더 형이 있다. 실제로 Dictionary <String, Int>는 [String:Int]로 표시한다.


사전 리터럴

Dictionary <Key, Value> 형은 ["key1": "value1", "key2": "value2"]와 같은 사전 리터럴로 표현한다. 예로 키가 String형 값을 Int형 사전 리터럴은 [String: Int] 형과 추론된다.  사전 리터럴은 키와 값은 :으로 연결하며 페어링 한 요소를 , (콤마)로 구분해서 []에 열거한다.


let a = ["a": 1, "b": 2]


사전 리터럴은 Dictionary <Key, Value> 형의 Key형은 키형에서 Value형은 값형에서 유추된다. 예로, 키가 String형값을 Int형 사전 리터럴은 [String: Int] 형 추론을 한다. 요소가 하나도 존재하지 않거나 키와 값에 여러 가지 형이 혼재하는 경우는 사전 리터럴 형을 유추하지 못할 수 없다.


let a = ["a": 1, "b": 2]


또한, 요소가 하나도 존재하지 않거나 키 및 값에 여러 가지 형이 존재하는 경우 사전 리터럴 형을 유추하지 못할 수 있고 이런 경우 변수 및 상수형 주석을 사용하여 형을 명시해야 한다. 아래 예는 빈사 전 리터럴 [:]의 할당 정보에 대해 [String:Int] 형의 형주석을 추가하여 형을 결정한다.


let a: [String: Int] = [:]


Dictionary <Key: Hashable, Value> 형이며 Key형에 제한되어 있다. : Hashable부분은 형식 제약조건이며 Key형에 Hashable프로토콜을 지키는 것으로 제한한다.

Hashable프로토콜은 그 형의 값을 바탕으로 해시값이 계산 가능한지를 나타내는 프로토콜로 해시값은 원래 값에서 특정 알고리즘에서 산출되는 Int형값이다. Key형이 Hashable프로토콜을 지킬 필요가 있는 해시값이 키의 고유성을 필수로 한다.

Hashable프르토 콜의 형은 String형이나 Int형이 있고 예로 String형값 "a"의 hashValue은 값이 있고 Int형값 1, hasValue는 1이 되고 있다. 반대로 Hashable 프로토콜을 지키지 않는 형은 Array <Element> 형등이 있다. Key형과 달리 Value형은 형제한이 없다. 따라서 Value형에 [Int] 형을 적용하여 [String: [Int]]형으로 하거나 [String: Int] 형으로 처리할 수 있다.

Key형과는 다른 형의 키와 Value형은 다른 형의 값을 설정하면 컴파일 오류가 발생한다.


Dictionary <Key, Value> 형 조작하기

Dictionary <Key, Value> 형의 값에 접근하려면 서브 스크립트를 사용한다. 서브 스크립트 인수는 Key형 값으로 지정한다. 예로 [String: Int] 형의 값에 접근할 경우, 아래와 같이 처리한다.


let a = ["a": 1]

let b = a ["a"] // 1 (Optional <Int> 형)


Dictionary <Key, Value> 형은 Array <Element> 형과 다르게 서비스 크립트에서 값이 없는 경우에도 런타임 오류가 발생하지 않는다. 대신 서비스 크립트가 리턴하는 값은 nil을 확인하고 처리하기 위해 Optional<Value>형값을 리턴하기 위해 사용된 값이 nil이 아닌 것을 확인하고 값을 사용해야 한다.


let a = ["k1": "v1"]

let v1 = a ["k1"]!= nil // 참

let v2 = a ["k2"]!= nil // 거짓


Dictionary <Key, Value> 형 값의 변경, 추가, 삭제도 서브 스크립트를 사용한다. 서브 스크립트 인수 Key형 값을 지정하고 대입 연산자 =를 사용하여 새 값을 지정한다. 서비스 크립트에서 지정한 키가 이미 존재하는 경우 값 변경이 되고 키가 존재하지 않으면 신규 추가가 되고 새 값에 nil을 설정하면 값이 삭제된다.


// 변경

var a1 = ["key": 1]

a1 ["key"] = 3

a1 // ["key": 3]

// 추가

var a2 = ["key1": 1]

a2["key2"] = 2

a2 // ["key1": 1, "key2": 2]

// 삭제

var a3 = ["key": 1]

a3["key"] = nil

a3 // [:]



9. 범위형

범위형은 Range<Bound>형, CountableRange<Bound>형, ClosedRange<Bound>형, CountableClosedRange<Bound>형등이 있다. 이들 종류에 따라 다양하게 조합해서 사용할 수 있고, 계산 가능한 범위는 Int형 범위와 같이 범위에 포함되는 값도 정해지는 거이다. 계산이 불가능한 범위는 Double형 범위와 같이 범위에 포함되는 값수가 정해지지 않는다. 실제로 Range<Float>형이나 CountableClosedRange<Int>형처럼 Bound형에 구체적인 형을 지정해서 사용한다.


범위 연산자

범위 연산자는 범위형 값은 범위 연산자를 이용하여 생성한다. 범위 연산자는 반개 구간을 만들 때 ..< 연산자와 닫힌 간격을 만드는 ... 연산자 두가지를 사용한다.

반개 구간은 범위의 시작점 또는 끝점 중 하나만 포함하는 구간이다.


범위형 ~ 구간

Range<Bound> ~ 반개 구간 (계산 불가능)

CountableRange<Bound> ~ 반개 구간 (계산 가능)

ClosedRange<Bound> ~ 닫힌구간 (계산 불가능)

CountableClosedRange<Bound> ~ 닫힌구간(계산 가능)

Swift언에서 오른쪽 열린 구간은 존재하지 않기 때문에 앞으로는 왼쪽 열린 구간의 반개 구간을 사용한다.

..< 연산자를 사용하여 반개 구간을 나타내는 Range<Bound>형과 CountableRange<Bound>형 값을 생성할 수 있다. ..< 연산자는 삽입한 연산자는 좌측에 범위의 시작값, 오른쪽에 범위 종료 값을 지정한다. 예로 Double형 1.0 이상 3.5 미만의 구간을 나타내는 Range<Double>형 값을 만들기 위해 1.0 ..< 4.5처럼 선언한다.

..< 연산자 양쪽이 Int형인 경우 계산 가능한 CountableRange<Bound>형 값이 생성된다. CountableRange<Bound>형 요소를 열거하기 위한 프로토콜로 Sequence프로토콜을 지키기 때문에 for-in문을 사용하여 해당 요소에 순차적으로 접근할 수 있다. 반개 구간이기 때문에 1 ..< 5는 5가 범위에 포함되지 않는 것에 주의하자.


let range = 1..<5 // CounatableRange(1..<5)

for value in range {

   print(value)

}


..< 연산자 양쪽이 Int형이라고 해도 형주석을 사용하면 Range<Bound>형 값도 생성할 수 있다.


let range: Range<Int> = 1..<5


한편, Double형 범위는 계산 불가능하기 때문에, 형주석을 사용해도 CountableRange<Bound>형 값을 생성할 수 없다.


let range: CountableRange<Double> = 1.0 ..< 4.5 // 컴파일오류


... 연산자는 닫힌 간격을 범위의 시작점과 끝점을 포함한 구간으로 ClosedRange<Bound>형과 CountableClosedRange<Bound>형 값을 생성할 수 있다. ... 연산자도 삽입시 연산자는 좌측에 범위의 시작값, 오른쪽에 범위 종료값을 지정한다. 예로 Double형 1.0이상 4.5 이하의 범위를 나타내는 ClosedRange<Double>형 값을 생성하려면 1.0 ... 4.5로 선언한다. ... 연산자 양쪽이 Int형인 경우 계산 가능한 CountableClosedRange<Bound>형값이 생성된다. Sequence프로토콜을 지키기 때문에 for-in문을 사용하여 해당 요소에 순차적으로 접근할 수 있다. 닫힌 간격이기 때문에 1 ... 5일 경우 5가 포함된다.


let range = 1 ... 5 // CountableCLosedRange(1...5)

for value in range {

    print(value)

}


... 연산자 양쪽이 Int형이라고 해도, 형주석을 사용하면 ClosedRange<Bound>형 값도 생성할 수 있다.


let range: ClosedRange<Int> = 1...5


한편, Double형 범위는 계산이 불가능하기 때문에 형주석을 사용해도 CountableClosedRange<Bound>형 값을 생성할 수 없다.


let range: CountableClosedRange<Double> = 1.0 ... 4.5 // 컴파일오류


또한, ..< 연산자와 ... 연산자에 의해 범위형 값을 생성하는 경우, Bound형은 연산자 양쪽 값형에서 유추한다. 예로 양쪽갑 형이 Int형이면 Bound형은 Int형이 되고, Double형이면 Bound형도 Double형이다.


let i = 1 ..< 5 //CountableRange<Int>형

let d = 1.0 ..< 5.0 //Range<Double>형


정수 f에 Range<Float>형에 형주석을 추가하여 ..< 연산자결과형을 Range<Float>형으로 선언한다.


let f: Range<Float> = 1 ..< 5 //Range<Float>형


Bound형은 대소관계를 비교하기 위한 프로토콜로 Comparable프로토콜을 지켜 다양한 형을 적용할 수 있지만 두가지 형은 같아야 한다. 시작 값이 Int형이면 끝 값도 Int형이어야 한다.


let a1 = 1 ..< 5

let a2 = 1 ..< "a"


범위형 사용하기

범위형은 범위 끝 값을 리턴하는 속성 lowerBound(범위 시작 값 리턴)와 upperBound(범위 끝 값 리턴)가 준비되어 있다.


let a = 1.0 ..< 5.0 //Range(1.0 ..< 5.0)

a.lowerBound //1

a.upperBound //5


let b = 1 ..< 5 //CountableRange(1 ..< 5)

b.lowerBound //1

b.upperBound //5


let c = 1.0 ... 5.0 //ClosedRange(1.0 ... 5.0)

c.lowerBound //1

c.upperBound //5


만약, 형 범위에 특정값이 들어있는지를 확인하려면 contains(_:)메소드를 사용한다. 결과는 Bool형값을 리턴해준다.


let a = 1 ... 5 //CountableClosedRange(1...5)

a.contains(3) //참

a.contains(7) //거짓



10. Optional<Wrapped>형

Optional<Wrapped>형은 값이 있는지 비어 있는지를 나타내는 형이다. Swift 언어의 변수 및 상수는 기본적으로  nil을 허용하지 않지만 nil허용이 필요할 경우 Optional<Wrapped>형을 사용한다. 이떄 Wrapped형을 실제로는 Optional<Int>형처럼 구체적인 형을 지정해서 사용한다. Wrapped 형에는 어떤 형이라도 지정할 수 있다.


Optional<Wrapped>형의 2가지 케이스

Optional<Wrapped>형은 Wrapped형의 값이 있는지, 없는지 2가지를 나타낸다.


enum Optional<Wrapped> {

    case none

    case some(Wrapped)

}


열거형은 여러가지 식별자를 요약한 형으로 각각의 식별자를 케이스라고 한다. Optional<Wrapped>형은 .none, .some 두 가지 케이스를 정의하고 있다. .none은 값이 없는 경우, 즉, nil과 동일하고 .some은 값이 존재하는 경우이다.


let n = Optional<Int>.none

print(".none: \(n)")

let s = Optional<Int>.some(3)

print(".some: \(s)")


Optional<Wrapped>형의 .none과 nil리터럴이 매핑되어 있기 때문에 값이 .none이면 nil이라고 하기도 한다.

.some값을 생성하는 경우 해당 값에서 형 추론을 할 수 있는데 이를 이용하면 아래와 같이 작성할 수 있다.


let s = Optional.some(3)


한편, .none을 생성하는 경우 형 추론할 수 있는 값이 없기 때문에 그대로 <Wrapped>를 생략할 수 없다.  .none생성에서 <Wrapped>을 생략하려면 형주석을 대입하는 쪽의 변수와 상수형을 지정하는 방법에서 형을 결정해야 한다.


let n: Int? = Optional.none


.some생성은 값에서 형 추론이 가능하지만, .none생성은 형을 명시해야 한다.


Optional<Wrapped>형 값 생성하기


var a: Int?

a = nil // nil리터럴 대입에 의한 .none생성

a = Optional(3) // 이니셜라이저에 의한 .some 생성

a = 3 // 대입에 의한 .some생성


열거형 케이스로 만드는 것보다 간단하게 할 수 있기 때문에 편리하다.

또한 Optional<Wrapped>형의 .none은 nil리터럴을 대입하여 생성할 수 있다.


let a: Int? = nil

let b: String? = nil

print(type(of: a), a) // Optional<Int> nil

print(type(of: b), b) // Optional<String> nil


단, nil리터럴은 기본형이 존재하지 않기 때문에, nil리터럴 대입쪽 변수 및 상수형은 형주석등을 우선적으로 해야 한다.


let a: Int? = nil //문제없음

let b = nil //상수형이 결정되지 않았기 때문에 컴파일 오류


또한 .some값을 인수로 받아 초기화 Optional(_:)를 사용하여 생성이 가능하며 이니셜라이저에 전달된 인수에서 형추론된다.


let a = Optional(10)

let b = Optional("한")

print(type(of: a), a)

print(type(of: b), b)


변수 및 상수형에 형주 석등을 통해 Optional<Wrapped>형인 경우 Wrapped형값을 대입하여 .some을 만들 수 있다.


let a: Int? = 10

print(type(of: a), a) // Optional<Int> Optional(10)


Optional<Wrapped>형 풀기 (값 얻기)

값을 가지고 있지 않은 상태도 고려해야 하기 때문에 Wrapped형 변수 및 상수처럼 취급하기 어렵다.


let a: Int? = 10

let b: Int? = 10

a + b // 컴파일 오류


Optional<Wrapped>형값을 가지는 Wrapped형값에 대한 작업을 하려면 Optional<Wrapped>형값에서 Wrapped형값을 추출해야 한다.


선택적 바인딩

?? 연산자

강제 풀기(Unwrap)


선택적 바인딩(Optional Binding)은 조건 분기문이나 반복문 조건에 Optional <Wrapped> 형 값을 전달값의 유무에 따라 처리를 전환하는 값이 존재하면 Wrapped형 추출방법이다. 선택적 바인딩은 if-let문을 이용해서 처리한다.


if let 상수명 = Optional<Wrapped> 형값 {

   값이 존재하는 경우 실행되는 문

}


아래 예는 a에 값이 존재하기 때문에 b에 값을 할당한 if문을 실행문이 실행된다.


let a = Optional("한") // String?형

if let r = a {

    print(type(of: r) //a에 값이 있는 경우만

}


??연산자는 Optional<Wrapped>형에 값이 없으면 기본값을 지정하려면 중간값 연산자?? 를 사용한다. ??연산자는 왼쪽 Optional<Wrapped>형값, 오른쪽에는 Wrapped형값을 얻는다.


let a: Int? = 10

let b = a ?? 3 // 10


강제풀기(forced unwrapping)은 !연산자에 의해 Optional<Wrapped>형에서 Wrapped형의 값을 추출하는 방법이다. 강제풀기를 하려면  값을 변환하는 식끝에 !연산자를 추가한다.


let a: Int? = 10

let b: Int? = 10

a! + b! //20


주의해야 할 점은 값 존재가 상당히 명백한 부분이나 값이 존재하지 않으면 프로그램을 종료하고 싶은 부분이 아닌 경우에는 강제풀기를 사용하는 것을 권장하지 않는다.


선택적 체인(Optional Chaining)

선택적 체인은 풀기를 하지 않고 Wrapped형 속성이나 메소드 접근하는 방법이다. Optional<Wrapped>형에서 Wrapped형 속성에 접근하려면 일단 선택적 바인딩으로 랩핑해야 한다.


let a = Optional(3.0) 

let b: Bool?

if let x = a {

    b = x.isInfinite

} else {

    b = nil

}

print(b) //Optional(false)


램핑하지 않고 Wrapped형 속성이나 메소드에 접근할 수 있는 방법이 있다.


let a = Optional(3.0)

let b = a?.isInfinite

print(b) //Optional(false)


다음 예는 선택적 체인을 통해 contains(_:)메소드를 호출하여 범위에 지정값이 포함되는지를 체크할 수 있다.


let a = Optional(0 ..< 20)

let x = a?.contains(13)

print(x) // Optional(true)


선택한 체인은 Optional<Wrapped>형 변수 및 상수가 nil이 있으면 이후 작성된 속성이나 메소드에 접근하지 않고 nil을 리턴한다.


ImplicityUnwrappedOptional<Wrapped>형

값이 있는지 빈값인지를 nil을 허용하는 형식은 Optional<Wrapped>형 이외에 ImplicityUnwrappedOptional<Wrapped>형이 있다. ImplicityUnwrappedOptional<Wrapped>형값에 접근시 암시적으로 강제풀기를 하기 위한 값이 들어 있는지 없는지를 허용하면서 Wrapped형과 같게 사용할 수 있다.


var a: Int!

a = nil // nil리터럴 대입에 의한 .none생성

a = ImplicityUnwrappedOptional(1) // 이니셜라이저에 의한 .some생성

a = 1 //대입에 의한 .some생성



var a: String? = "한"

var b: String! = "국"

print("a: type=\(type(of: a)), value=\(a)")

print("b: type=\(type(of: b)), value=\(b)")

var c = b

a = b

b = c

print("a: type=\(type(of: a)), value=\(a)")

print("b: type=\(type(of: b)), value=\(b)")



11. Any형

모든 형을 나타내는 Any형에 대해서 알아보자. Any형은 모든 형 암묵적으로 별도 프로토콜이 구현되어 있다. Any형의 변수 및 상수는 어떤 형도 대입한다.


let s: Any = "대한민국"

let x: Any = 12345


Any형은 지금까지의 형처럼 리터럴이나 이니셜라이저에 의한 값을 생성하는 것은 아니다.

Any형 변수 및 상수에 대입하면 원래 형의 정보가 손실되어 버리기 때문에 원래 형이 가능했던 조작을 할 수 없을 수 있다.


let a: Any = 10

let b: Any = 11

a + b //컴파일 오류


이런 Any형에 의한 대입값에 대한 조작이 어려워지기 때문에 가능한 Any형 사용을 피하는 것을 추천한다.


12. 튜플형

여러가지 형을 하나의 형으로 취급 처리할 수 있는 것이 튜플형이다. 튜플형을 정의하려면 요소가 되는 형을 ()으로 구분하여 (형1, 형2, 형3) 형태로 열거한다. 튜플형의 요소에는 어떤 형으로도 지정할 수 있고 원소갯수에 제한없다.


var tuple: (Int, String)


튜플형 값은 튜플이며 튜플을 생성하려면 요소가 되는 값을 ()에 구분하여 (요소1, 요소2, 요소3)처럼 열거한다.


var t: (Int, String)t = (1, "한")


요소 접근하기

튜플 요소에 접근하려면 색인 사용 및 요소명 접근, 대입접근 등이 있다.

색인사용은 튜플 요소는 인덱스를 통해 접근할 수 있다. 변수 및 상수를 지정하고 변수명 인덱스라는 형식으로 접근한다.


let t = (1, "한")

let i = t.0 //1

let s = t.1 //"한"


요소명에 접근하려면 튜플을 정이할 때 각 요소명을 붙여 해당 이름을 통해 요소를 접근할 수있다. 요소명을 정의하려면 튜플요소 앞에 요소명:을 추가하여 (요소명1: 요소1, 요소명2: 요소2)형태로 작성한다.


let t = (int: 1, string: "한")

let i = t.int // 1

let s = t.sting //"한"


대입접근은 튜플에 요소 몇개가 있는 변수 및 상수를 ()내에서 구분하여 열거한 것도 할당할 수 있다.


let i: Int

let s: String

(i, s) = (1, "한")

i //1

s //"한"


또한, 여러개의 변수 및 상수를 ()내에 동시에 선언할 수 있다.


let (i, s) = (1, "한")

i // 1

s // "한"


Void형

요소 형이 0개의 튜플형을 Void형이라고 하며 값이 존재하지 않는 것이다.


() //Void형


nil리터럴도 값이 존재하는 것을 나타내는데 사용하지만 이것은 값 유무 중 무를 나타내는 것이다. 한편 Void형은 값이 존재하는장소가 아님을 나타낸다. Void형은 이런 성질은 함수 리턴값이 없는 것을 나타내는 용도로 사용된다.


13. 형변환

형변환은 변수 및 상수형보다 범용적인 형이나 구체적인 형으로 취급하는 경우이다.


형 판정하기

값형이 특정형인지 연부를 확인하려면 is 연산자를 사용한다. is연산자는 좌측에 검증할 식을 넣고 우측에 검증하려는 형을 넣는 연산자이다. 결과는 Bool형값을 리턴한다.


let a: Any = 12 

let b = a is Int // 참


상위형 캐스팅

상위형 케스팅은 연산자 as를 사용하고 좌측값을 우측형값으로 취급한다.


let a = "한국" as Any // String형을 Any형으로 상위형 캐스팅


하위형 캐스팅

하위형 캐스팅은 연산자 as?를 사용한다.


let a = 12 as Any

let b = a as? Int //Optional(1)

let x = a as? String //nil















































매거진의 이전글 1. Swift는 어떤 개발언어인가?
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari