개발자가 사랑하는 라이트 모드

 

튜플 Tuple

튜플은 복수의 값을 하나의 그룹으로 합친 것이다.

그룹 내에 모든 값이 같은 타입일 필요는 없다.

 

데이터를 저장하는 간단한 방법으로, 클래스 혹은 구조체를 대체할 수 있다.

함수에서 return 되는 여러 개의 값, 타입이 다른 값 등을 저장하기에 안성맞춤이다.

또한 class에서 지원하는 기능을 지원한다. (computed property, instance method, ...)

 

아래와 같은 방법으로 선언한다.

  var team = ("Boston", "Red Sox", 97, 65, 59.9)

 

역으로, 하나로 묶여있는 튜플을 여러 개의 변수에 나누어 할당(decompose)할 수도 있다. 

var team = ("Boston", "Red Sox", 97, 65, 59.9)
var (city, name, wins, losses, percent) = team

 

튜플의 값을 인덱스로 가져올 수 있다. 배열의 subscript 방식과는 형태가 다르다.

var team = ("Boston", "Red Sox", 97, 65, 59.9)
var city = team.0 // "Boston"
var name = team.1 // Red Sox"
var wins = team.2 // 97
var losses = team.3 // 65
var percent = team.4 // 59.9

 

지금까지 우리가 다룬 것은 unnamed tuple이다. value에 대응하는 이름이 없지 않은가 ?

즉, named tuple을 만드는 것도 가능하다.

이 방법을 사용하면 decomposition 단계를 건너뛸 수 있다.

이름으로 값에 접근하는 것 또한 가능하다.

var team = (city:"Boston", name:"Red Sox", wins:97, losses:65, percent:59.9)

print(team.0) // "Boston"
print(team.city) // Boston"

 

열거형 Enumeration

열거형은 관련된 타입끼리 묶어서, type-safe한 방법으로 활용하기 위한 데이터 타입이다.

줄여서 Enum이라고도 부른다. 이넘 ~

 

일반적으로 열거형은 name, raw type, member(==member value), raw value로 구성된다.

아래는 열거형의 기본적인 구조이다. (name, member 만을 활용)

enum Planets { 		// name, 대문자로 시작해야 한다.
    case mercury	// member, 대문자/소문자 상관 없지만 소문자 시작을 권장한다.
    case venus 		// member
    case earth 		// ...
    case mars
    case Jupiter
    case Saturn
    case Uranus
    case neptune
}

 

하나의 케이스에 여러 개의 member를 묶을 수도 있다.

enum Planets {
    case mercury, venus, earth, mars, jupiter
    case saturn, uranus, neptune
}

 

열거형의 값은 점 표현식으로 사용할 수 있다.

var planetWeLiveOn = Planets.earth // Planets 타입으로 추론
var furthestPlanet = Planets.neptune // Planets 타입으로 추론

 

타입 추론이 완료된 뒤에는, Planets 접두사 없이도 사용할 수 있다.

  planetWeLiveOn = .mars

 

열거형은 주로 값을 equals operator(==) 혹은 switch statement에서 비교 대상으로 사용하기에 적합하다.

// equals operator
if planetWeLiveOn == .earth {
    print("Earth it is")
}

// switch statement
switch planetWeLiveOn {
    case .mercury:    
        print("We live on Mercury, it is very hot!")
    case .venus:
        print("We live on Venus, it is very hot!")
    case .earth:
        print("We live on Earth, just right")
    case .mars:
        print("We live on Mars, a little cold")
    default:
        print("Where do we live?")
}

 

초기 타입 raw type, 초기 값 raw value

열거형의 raw type은 정수형에 한정되지 않는다. (String, Character, Int, Float(사용이 조금 어렵다), CustomType, ...)

열거형은 여러 개의 case가 있고, 각각은 raw type에 대응하는 raw value를 가질 수도 있다.

 

아래의 구조를 통해 직접 확인하자.

enum Devices: String { // raw type == String
    case MusicPlayer = "iPod" // rawValue == iPod
    case Phone = "iPhone" // rawValue == iPhone
    case Tablet = "iPad" // rawValue == iPad
}

 

저장된 rawValue는 점 표현식으로 사용할 수 있다.

print("We are using an \(Devices.Tablet.rawValue)") 
// "We are using an iPad"

 

raw type이 정수형인 경우에, auto-incremented 기능이 있다.

어떤 member에게 rawValue를 설정하면, 다음 member부터는 +1씩 커지는 rawValue를 부여한다.

enum Planets: Int {
    case Mercury = 1
    case Venus // 2
    case Earth // 3
    case Mars // ...
    case Jupiter
    case Saturn
    case Uranus
    case Neptune
}

 

rawValue를 설정하지 않으면 기본적으로 0부터 시작한다.

enum Planets: Int {
    case Mercury // 0
    case Venus // 1
    case Earth // 2
    case Mars = 100
    case Jupiter // 101
    case Saturn
    case Uranus
    case Neptune
}

연관 값 associated values

다소 헷갈리는 개념이다.

 

초기 값으로 여러 개의 값을 보관하려면 콤마로 구분하는 게 고작이다.

이 값을 활용하려면 콤마를 기준으로 파싱해 주어야 한다.

 

반면 연관 값은 더 많은 정보를 저장할 수 있게 해준다.

연관 값은 어떤 타입도 가능하며, member 사이에서도, member 내에서도 타입이 달라도 된다.

 

구조부터 즉시 확인해보자.

// raw value
enum AppleDevice: String {
    case iPhone = "X, 256GB"
    case iMac = "27, Pro, 300만원"
    case macBook = "Air, 1kg, 150만원"
}

// associated value
enum AppleDevice {
    case iPhone(model: String, storage: Int) // named tuple
    case iMac(size: Int, model: String, price: Int)
    case macBook(String, Int, Int) // unnamed tuple
}

 

위의 구조를 확인해 보면, 연관 값을 갖는 열거형에는 raw type이 없다.

unnamed associated values / named associated values 형태로 나뉜다.

 

연관값은 변수를 선언할 때, member의 인자로 값을 전달한다.

주로 switch statement를 활용해 연관 값을 비교하는 형태로 쓰인다.

 

아래에서 연관 값의 용례를 확인해보자.

var gift = AppleDevice.iPhone(model: "X", storage: 256)

switch gift {
case .iPhone(model: "X", storage: 256):
    print("iPhone X and 256GB")
case .iPhone(model: "X", _): // 와일드카드 패턴 사용 가능
    print("iPhone X")
case .iPhone: // 연관값 생략 가능
    print("iPhone")
case .iPhone(let model, let storage): // 블록 내부에서 연관값을 사용할 땐 상수로 바인딩 // 값을 변경할 때는 var 로 변경가능
    print("iPhone \(model) and \(storage)GB")
case let .iMac(size, model, price): // 모든 연관값을 동일한 형태로 바인딩한다면, let 키워드를 열거형 케이스 앞에 표기하는 것도 가능
    print("iMac \(size), \(model), \(price)")
}

 

마지막으로 열거형의 raw type이 정수형이 아니더라도 member끼리 비교하는 방법이 있다.

열거형이 Comparable 프로토콜을 따르게 하면 된다.

enum Grades: Comparable {
    case f
    case d
    case c
    case b
    case a
}

let acceptableGrade = Grades.c
let testOneGrade = Grades.b

if  testOneGrade < acceptableGrade {
    print("Grade is unacceptable")
} else {
    print("Grade is acceptable")
}

// 출력: "Grade is acceptable"
// 마치 Int의 auto-incremented처럼 f < d < c < b < a의 위계가 생기는 듯하다. rawValue에 접근하면 컴파일 에러가 발생한다.

 

연산자 Operator

할당 assignment

let x = 1
var y = "Hello" 
a = b

비교 Comparison

2 == 1 //false, 2 does not equal 1
2 != 1 //true, 2 does not equal 1
2 > 1 //true, 2 is greater than 1
2 < 1 //false, 2 is not less than 1
2 >= 1 //true, 2 is greater or equal to 1
2 <= 1 //false, 2 is not less or equal to 1

산술 Arithmetic

var x = 4 + 2 //x will equal 6
var x = 4 – 2 //x will equal 2
var x = 4 * 2 //x will equal 8
var x = 4 / 2 //x will equal 2
var x = "Hello " + "world" //x will equal "Hello World"

 

나머지 Remainder

var x = 10 % 3 //x will equal 1 
var x = 10 % 6 //x will equal 4

복합 Compound

var x = 6
x += 2 //x now is 8
x -= 2 //x now is 4
x *= 2 //x now is 12
x /= 2 //x now is 3

범위 closed range / half-open range

// closed range
for i in 1...3 {
    print("Number: \(i)")
}

// Number: 1
// Number: 2
// Number: 3

// half-open range
for i in 1..<3 {
    print("Number: \(i)")
}

// Number: 1
// Number: 2

삼항 ternary conditional operator

// 형태: (boolValue ? valueA : valueB)

var x = 2
var y = 3
var z = (y > x ? "Y is greater" : "X is greater") // z equals "Y is greater"

 

논리 Logical

// NOT
var x = true
var y = !x //y equals false

// AND
var x = true
var y = false
var z = x && y //z equals false

// OR
var x = true
var y = false
var z = x|| y //z is true

 

 

참고

<Mastering Swift 5.3>, Jon Hoffman, 6th Edition

Chapter 3: Learning about Variables, Constants, Strings, and Operators

 

https://onelife2live.tistory.com/13

+ Recent posts