본문 바로가기

Programming/iOS

[Swift] types

반응형

개인적으로 공부하기 위해 번역해서 남겨둔다.


Swift에는 2가지 type이 있다.

  • named types
    • 이름이 정해진 type이다.
    • class, struct, enumeration, protocol 를 포함한다.
    • 사용자가 만든 임의의 class이름을 Person 이라고 하면 Person또한 named type이며 user-defined named type이라 한다.
    • standard library에는 array, dictionary 등 많은 named type들이 제공된다.
    • data type은 number, character, string 등의 named type 을 말한다. Swift standard library에 structur로 구현되어 있다. 필요에 따라서 원하는 동작을 extend할 수 있다. (objc에 있는 extend기능을 말한다. swift에도 있음)
  • compound types
    • 이름이 없다.
    • named type과 다른 compound type을 포함한다.
      예) (Int, (Int,Int)) -> named type Int와 compound type(Int,Int)로된 compound type
    • 두가지의 compound type이 있다.
      • function type
      • tuple type


Type Annotation

변수나 식의 타입을 명시적으로 지정한다.

  • let someTuple: (Double, Double) = (3.14159, 2.71828)

someTuple은 (Double, Double)의 tuple type으로 지정되었다.

  • func someFunction(a: Int) { /* ... */ }

parameter a는 Int type으로 지정되었다.


Type Identifier

type identifier는 named type이거나 named/compound type의 별칭(alias)이다.

(C계열의 typedef 와 유사)

  • typealias Point = (Int, Int)

(Int, Int) tuple type을 Point라는 이름으로 type identifier를 지정함.

  • let origin: Point = (0, 0)

하나의 type형태로 사용할 수 있음. 다음과 같은 의미이다.

  • let origin: (Int, Int) = (0, 0)
  • var someValue: ExampleModule.MyType

다른 모듈이나 다른 type에 중첩된 type일 경우 . 을 사용하여 identifier를 이용할 수 있다.


Tuple Type

중괄호 안에서 comma(,)로 구분된 0개 이상의 type list 이다.

ex) (), (Int), (Int, Double) 

tuple type은 함수 return에서 사용한다. 함수에서 2개 이상의 값을 하나의 tuple type로 return할 수 있다.

element name은 colon(:) 다음에 identifier로 되어 있다. 

ex) (name : String, age: Int)

Void 는 비어있는 tuple type이다. ()

하나의 element만 있다면 tuple type이 아닌 element type이 된다.

(Int)는 (Int)가 아니라 Int이다.


Function Type

(->) 로 구분되는 parameter, return type으로 구성된 function, method, closure 의 type을 function type이라 한다.

  • parameter type -> return type

parameter type, return type은 tuple type도 가능하다. 일반 function, method와 같이 0개 이상의 parameter, 0개 이상의 return value을 지원한다. (parameter, return이 일반 function, method와 같다고 보면 됨)

parameter type이 ()이고 return이 있을 경우 auto_closure attribute를 적용할 수 있다.

autoclosure function은 특정 expression을 캡쳐 한다.

  • func simpleAssert(condition: @auto_closure () -> Bool, message: String) {
  • if !condition() {
  • println(message)
  • }
  • }
  • let testNumber = 5
  • simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")

(testNumber %2 == 0 이 캡쳐되어 condition이 된다)

가변 인자 매개변수(variadic parameter) 는 parameter type중 가장 마지막에 위치해야 한다. 문법적으로 가변 인자 매개변수는 기본 type name과 그 뒤에 점 세개 (...) 로 구성된다. ex) Int...  
가변 인자 매개변수는 array로 취급된다. Int... 은 Int[] 로 취급된다.

in-out parameter를 사용하기 위해서 parameter type 접두사로 inout keyword를 붙여준다. 가변 인자 매개변수에는 inout keyword를 쓸수 없다.

커리함수(curried function)은 중첩 function type과 같다. 예를 들어 

  • func addTwoNumbers(a: Int)(b: Int) -> Int {
  • return a + b
  • }
  • addTwoNumbers(4)(5) // Returns 9

커리함수의 function types은 오른쪽에서 왼쪽으로 그룹화된다. 예를 들어 Int->Int->Int 는 Int->(Int->Int)이다. parameter로 Int를 받아서 (Int->Int) 라는 함수를 return한다. 


Array Type

named type Array<T>를 사용한다. 문법적으로 간단하게 type 이름 뒤에 대괄호([])를 이용합니다. 

아래 두개의 문법은 동일하다.

  • let someArray: String[] = ["Alex", "Brian", "Dave"]
  • let someArray: Array<String> = ["Alex", "Brian", "Dave"]

someArray[0] 은 index 0인 element 인 "Alex"이다. (다른 언어 array와 동일)


Optional Type

named type Optional<T>를 문법적으로 간단하게 하기 위해 Swift에서는 접미사 (?)를 정의했다. 아래 두개의 문법이 동일하다.

  • var optionalInteger: Int?
  • var optionalInteger: Optional<Int>

Optional<Int>는 선택적으로 Int를 가질 수 있다. type name 과 (?) 사이에는 빈 공간(whitespace)이 있으면 안된다.

Optional<Int>는 None, Some(T) 두가지 경우가 있다. 모든 type이 optional type으로 선언 가능하다. 중괄호()로 범위를 지정하여 (?)를 사용할 수 있다. ex) (Int[])?

만약 초기값을 지정하지 않는다면 기본으로 nil 값이 된다.

Optional은 LogicValue protocol을 따르므로 Boolean 이 된다. optional type T? 가 type T 의 어떠한 값이라도 가진다면 true와 같고 아니라면 false이다.

(!)연산자를 사용하면 optional 을 해제하여 nil 값을 가지고 있으면 runtime error를 발시킨다. 

즉 optional type은 wrap되어 있어 그 자체로 true/false로 나타낼수 있다. 하지만 정확히 값을 표현하고 싶을때 접미사로 (!) 연산자를 사용하면 optional type이 해제되어 실제 값으로 표현되는데 optional type이 아니므로 nil이 존재할 수 없다. 만약 nil이라면 runtime error가 발생한다.

optional expression 에서 연산자를 조건적으로 수행하기 위해 optional chaining, optional binding 을 사용할 수 있다. 만약 값이 nil이라면 실행할 연산자가 없어 runtime error가 발생된다.


Implicitly Unwrapped Optional Type

named type ImplicitylyUnwrappedOptional<T> 를 간단하게 표현하기 위해 접미사로 (!) 연산자가 정의되어 있다. 아래 두개의 정의는 같다.

  • var implicitlyUnwrappedString: String!
  • var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>

implicitlyUnwrappedString은 암시적 unwrapped optional string으로 선언되어 있다. type과 연산자 (!) 사이에는 공백(whitespace)가 없어야 한다.

암시적 unwrapped optional 은 optional을 사용하는 모든 곳에서 사용 가능하다.

선언할때 초기값을 지정하지 않으면 nil값으로 초기화된다.

암시적 unwrapped optional 은 사용할때 자동적으로 unwrapped 된다. 그러므로 unwrap하기 위해 (!)연산자를 사용하지 않아도 된다.

만약 nil값에 암시적 unwrapped optional 을 사용하면 runtime error가 발생한다.

조건적인 수행을 위해 optional chaining을 사용한다. 만약 값이 nil이면 실행할 연산자가 없어 runtim error가 발생된다.


Protocol Composition Type

지정된 protocol들을 각각 따르는 type..... 즉 지정된 protocol을 다 상속받은 protocol이라고 보면된다.

type annotations이나 generic parameters 에 사용된다.

  • protocol<Protocol 1, Protocol 2>

protocol<ProtocolA, ProtocolB, ProtocolC> 는 ProtocolA, ProtoclB, ProtocolC 를 상속받은 이름없는 protocol이다.

protocol<> 비어있는 protocol composition type이며 모든 type들이 protocol<>에 따르고 있다.


Metatype Type

class type 의 metatype 은 접미사로 .Type을 Protocol 의 metatype은 접미사로 .Protocol을 붙인다.

ex) SomeClass.Type , SomeProtocol.Protocol

.self 를 접미사로 붙이면 인스턴스가 아니라 type 자체를 return 한다. SomeClass.self 을 하는 경우 SomeClass의 인스턴스가 아니라 SomeClass 자체를 리턴한다. .dynamicType 은 인스턴스를 return한다.


Type Inheritance Clause

상속에 관한 내용이다. type 상속은 colon(:)과 함께 시작된다. type identifiers 사이에 comma(,)로 구분한다. 

Class type은 하나의 다른 superclass로 부터 상속받고 0개 이상의 protocol을 구현할 수 있다. 선언 중에는 superclass 의 name이 가장 먼저 와야 하며 뒤에 protocols 이 온다. 만약 다른 class로 부터 상속받지 않는다면 대신 protocol로 시작하게 된다.

class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {} class SomeClass: FirstProtocol, AnotherProtocol {}

다른 named type들도 상속받거나 protocols들을 구현했을 것이다. protocol type은 다른 protocols로 부터 상속받았을 것이다. 


Type Inference

type을 생략할 경우 Swift는 타입 추론을 사용한다. 예를 들어 var x: Int = 0 을 쓰는대신 type을 생략하여 var x = 0 을 쓸수 있다. 컴파일러는 정확히 x의 값이 Int라고 추론한다.  비슷하게 모든 타입이 다 추론 가능할때 type을 생략할 수 있다. 예를 들어 let dict: Dictionary = ["A":1] 은 Dictionary<String, Int>로 추론한다. 하지만.. let dict : Dictionary = ["A":1, 2:"B"] 는 <String, Int> 와 <Int, String>이 같이 사용되어 추론할 수 없어 컴파일 오류가 발생한다.

type 에 대한 정보는 expression tree 잎에서서 root 로 전달된다. var x: Int = 0 을 예로 들면 먼저 0의 type을 추론하고 이 정보를 root로 전달하게 된다. (변수 x로..)

type 정보가 반대 방향으로 전달 되는 경우도 있다. root 에서 잎(leaves)로... 예를 들면...

  • let e = 2.71828 // The type of e is inferred to be Double.
  • let eFloat: Float = 2.71828 // The type of eFloat is Float.

e는 기본적으로 leaves -> root 방향을 따라 2.71828 type인 double로 결정된다. 

eFloat 는 2.71828이 double이지만 Float으로 지정된다.


iOS Developer Library - The Swift Programming Language - Language Reference - Types

반응형