-
Chapter 10: StructuresRaywenderlich/Swift Apprentice 2022. 10. 22. 17:36
Version
Swift 5.5, iOS 15, Xcode 13
지금까지 Swift의 몇 가지 기본적인(fundamental) 구성 요소(building blocks)를 다루었다(covered). 변수(variables), 조건문(conditionals), 문자열(strings), 함수(functions), 컬렉션(collections)을 사용하여 세계를 정복(conquer)할 준비가 되었다. 뭐... 거의(well, almost).
복잡한(complex) 작업(tasks)을 수행(perform)하는 대부분의 프로그램(programs)은 더 높은(higher) 수준(levels)의 추상화(abstraction)에서 이점(benefit)을 얻는다(tasks).
Int
,String
,Array
외에도 대부분(most)의 프로그램(programs)은 당면한(at hand) 작업(task)의 도메인(domain)에 특화된(specific) 새로운 유형(types)을 사용한다. 예를 들어(for example), 사진(photos)이나 연락처(contacts)를 사용(track)하려면 지금까지 본 단순한(simple) 유형(types) 이상의 것이 필요(demands)하다.이 장(chapter)에서 최초로 명명된 유형 구조체(named type–structures)를 소개(introduces)한다. 구조체(structures)는 명명된 속성(named properties)을 저장(store)하고 작업(actions) 및 동작(behaviors)을 정의(define)할 수 있는 유형(types)이다.
String
,Int
,Array
처럼 구조체(structures)를 정의(define)하여 코드(code)에서 사용할 명명된 유형(named types)을 생성(create)할 수 있다. 이 장(chapter)이 끝나면, 자신만(own)의 구조체(structures)를 정의(define)하고 사용하는 방법을 알게 될 것이다.피자(pizza)와 함께 사용자 정의 유형(custom types)에 대한 모험(adventure)을 시작(begin)한다.
🍕
Introducing structures
당신이 Pizzaville이라는 마을(town)에 살고 있다고 상상해(imagine) 본다. 예상대로(as you might expect) Pizzaville은 놀라운(amazing) 피자(pizza)로 유명하다(known for). 당신은 Pizzaville에서 가장 인기(popular) 있고 가장 빠른(fastest) 피자(pizza) 배달(delivery) 식당(restaurant)인 "Swift Pizza"의 주인이다.
한 식당(restaurant)의 주인(owner)으로서, 배달(delivery) 지역(area)이 제한(limited)되어 있다. 잠재(potential) 고객(customer)이 배달(delivery) 기사(drivers)의 범위(range) 내(within)에 있는지 계산(calculates)하는 프로그램(program)을 작성(write)하려 한다. 프로그램(program)의 첫 번째(version) 버전(version)은 다음과 같다:
let restaurantLocation = (3, 3) let restaurantRange = 2.5 // Pythagorean Theorem 📐🎓 func distance(from source: (x: Int, y: Int), to target: (x: Int, y: Int)) -> Double { let distanceX = Double(source.x - target.x) let distanceY = Double(source.y - target.y) return (distanceX * distanceX + distanceY * distanceY).squareRoot() }
func isInDeliveryRange(location: (x: Int, y: Int)) -> Bool { let deliveryDistance = distance(from: location, to: restaurantLocation) return deliveryDistance < restaurantRange } isInDeliveryRange(location: (x: 5, y: 5)) // false
매우 간단(simple enough)하다.
distance(from:to:)
는 피자(pizza) 가게로 부터 얼마나 멀리 떨어져(far away) 있는지 계산(calculate)한다.isInDeliveryRange(location:)
는 너무 멀지(too far away) 않은 경우에만true
를 반환(return)한다.성공적인(successful) 피자(pizza) 배달(delivery) 사업(business)은 시간이 지나(eventually), 여러(multiple) 위치(locations)를 포함(include)하도록 확장(expand to)될 수 있으며, 배달 가능 여부 계산기(deliverable calculator)에 약간(minor)의 변형(twist)을 추가(adding)할 수 있다.
기존 코드(existing code)를 다음으로 바꾼다(replace):
let restaurantLocation = (3, 3) let restaurantRange = 2.5 let otherRestaurantLocation = (8, 8) let otherRestaurantRange = 2.5 // Pythagorean Theorem 📐🎓 func distance(from source: (x: Int, y: Int), to target: (x: Int, y: Int)) -> Double { let distanceX = Double(source.x - target.x) let distanceY = Double(source.y - target.y) return (distanceX * distanceX + distanceY * distanceY).squareRoot() } func isInDeliveryRange(location: (x: Int, y: Int)) -> Bool { let deliveryDistance = distance(from: location, to: restaurantLocation) let secondDeliveryDistance = distance(from: location, to: otherRestaurantLocation) return deliveryDistance < restaurantRange || secondDeliveryDistance < otherRestaurantRange } isInDeliveryRange(location: (x: 5, y: 5)) // false
isInDeliveryRange(location:)
는 두 위치(locations) 모두에서 피자(pizza)를 받을 수 있는지 확인(checks)한다.나중에는(eventually) 고객이 증가(rising)하고 사업(business)을 확장(expand)하여, 총(total) 10개의 매장(stores)으로 성장(grow)할 것이다. 그러면 이러한 모든 좌표(coordinates)와 범위(ranges) 집합(sets)을 확인(check)하기 위해 함수(function)를 계속 업데이트(updating)해야 할 것이다.
피자(pizza) 레스토랑(restaurants)을 계속 추적(track)하기 위해 x/y 좌표(coordinate) 튜플(tuples) 배열(array)을 만드는 것을 고려(consider)해 볼 수 있지만, 이는 읽기(read)와 유지보수(maintain) 모두 어렵다(difficult). 다행히(fortunately), Swift에는 문제(problem)를 단순화(simplify)하는 데 도움이 되는 추가 도구(additional tools)가 있다.
Your first structure
구조체(structures)는 관련 속성(properties) 및 동작(behaviors)을 캡슐화(encapsulate)할 수 있는 Swift의 명명된 유형(named types) 중 하나이다. 새 유형(type)을 선언(declare)하고 이름(name)을 지정(give)한 다음 코드(code)에서 사용할 수 있다.
피자(pizza) 사업(business) 예제(example)에서는 위치(locations)를 나타내기(represent) 위해, x/y 좌표(coordinate) 튜플(tuples)을 사용했다.
구조체(structures)의 첫 번째(first) 예(example)로, 위치(locations)를 튜플(tuples)에서 구조체(structure) 유형(type)으로 위치를 바꾼다(promote):
struct Location { let x: Int let y: Int }
이 코드 블록(block of code)은 구조체(structure)를 정의(defining)하기 위한 기본(basic) 구문(syntax)을 보여준다(demonstrates). 이 경우(in this case) 코드(code)는 x와 y 좌표(coordinates)를 결합(combines)하는
Location
유형(type)을 선언(declares)한다.기본(basic) 구문(syntax)은
struct
키워드(keyword)로 시작(begins with)하고, 그 뒤에 유형 이름(name of the type)과 한 쌍(pair)의 중괄호(curly braces)가 온다. 중괄호(curly braces) 사이(between)의 모든 것(everything)이 구조체(struct)의 구성요소(member)이다.Location
에서x
와y
는 모두 속성(properties)이다. 속성(properties)은 유형(type)의 일부(part)로 선언(declared)된 상수(constants) 또는 변수(variables)이다. 해당 유형(type)의 모든 인스턴스(instance)에는 이러한 속성(properties)이 있다. 이는 이 예(example)에서 모든(every)Location
에x
와y
속성(property)이 있음을 의미(means)한다.구조체(structure)를 인스턴스화(instantiate)하면, 지금까지 작업한 다른 유형(type)과 마찬가지로 상수(constant) 또는 변수(variable)에 저장(store)할 수 있다:
let storeLocation = Location(x: 3, y: 3)
Location
값(value)을 생성(create)하려면, 괄호(parentheses) 안에 매개변수 목록(parameter list)과 함께 유형(type) 이름을 사용한다. 이 매개변수 목록(parameter list)은 속성(properties)x
와y
에 대한 값(values)을 지정(specify)할 수 있다. 이는 이니셜라이저(initializer)의 예(example)이다.이니셜라이저(initializers)는 속성을 사용(start)하기 전에 모든 속성(properties)이 설정(set)되도록 한다(enforce). 이것은 Swift의 주요(key) 안전 기능(safety features) 중 하나이다. 실수로(accidentally) 초기화되지 않은(uninitialized) 변수(variables)를 사용(using)하는 것은 다른(other) 언어(other languages)에서의 주요(significant) 버그(bugs) 원인(source)이다. 또 다른(another) Swift의 편리한(handy) 기능(feature)은
Location
유형(type)에 이 이니셜라이저(initializer)를 선언(declare)할 필요가 없다는 것이다. Swift는 매개변수 목록(parameter list)에 있는 모든 속성(properties)을 가진 구조체(structures)에 대한 이니셜라이저(initializers)를 자동으로(automatically) 제공(provides)한다. 12장(chapter), "Methods"에서 이니셜라이저(initializers)에 대해 더 자세히 배울 것이다.이외에 연관된(involved) 범위(range)가 있다는 것을 기억(remember)할 것이다. 피자(pizza) 사업(business)이 확장(expanding)되고 있으므로, 다른(different) 식당(restaurants)과 관련된(associated with) 다양한(different) 범위(ranges)가 있을 수 있다. 다음과 같이 식당(restaurant)의 배달 지역(delivery area)을 나타내는(represent) 또 다른(another) 구조체(struct)를 만들(create) 수 있다:
struct DeliveryArea { let center: Location var radius: Double } var storeArea = DeliveryArea(center: storeLocation, radius: 2.5)
이제 변수(variable)
radius
속성(property)과 함께 상수(constant)center
속성(property)을 포함(contains)하는DeliveryArea
라는 새로운 구조체(structure)가 있다. 보다시피(as you can see) 구조체(structure) 값(value) 내부(inside)에 구조체(structure) 값(value)을 가질(have) 수 있다. 여기에서(here),Location
유형(type)을DeliveryArea
구조체(struct)center
속성(property)의 유형(type)으로 사용한다.Mini-exercise
피자(pizza) 주문(order)을 나타내는(represents) 구조체(structure)를 작성(write)한다. 피자(pizza)에 원하는 토핑(toppings), 크기(size) 및 기타(other) 옵션(option)을 포함(include)해야 한다.
Accessing members
DeliveryArea
가 정의(defined)되고 인스턴스화(instantiated)된 값(value)이 있으면(in hand), 이러한 값(values)을 어떻게 사용할 수 있는지 궁금할(wondering) 것이다.Strings
,Arrays
,Dictionaries
와 마찬가지로 점 구문(dot syntax)을 사용하여 구성 요소(members)에 접근(access)한다:storeArea.radius // 2.5
점 구문(dot syntax)을 사용하여 구성 요소(members)의 구성 요소(members)에 접근(access)할 수도 있다:
storeArea.center.x // 3
점 구문(dot syntax)으로 값(values)을 읽는(read) 방법과 유사하게(similar to) 할당(assign)할 수도 있다. 한 피자(pizza) 가게 위치(location)의 배달(delivery) 반경(radius)이 커지면(larger), 기존(existing) 속성(property)에 새 값(value)을 할당(assign)할 수 있다:
storeArea.radius = 3.5
속성(property)을 상수(constant) 또는 변수(variable)로 정의(determines)함에 따라, 수정 가능(change) 여부가 결정(defining)된다. 이 경우에는(in this case),
radius
를var
로 선언(declared)했기 때문에 새로 할당(assign to)할 수 있다.반면에(on the other hand)
center
는let
으로 선언(declared)했기 때문에 수정(modify)할 수 없다.DeliveryArea
구조체(struct)를 사용하면 피자(pizza) 레스토랑(restaurant)의 배달 범위(delivery range)를 변경(changed)할 수 있지만, 위치(location)는 변경할 수 없다.속성(properties)이 변수(variable) 또는 상수(constants) 인지 선택(choosing)하는 것 외에도, 초기화(initialized)된 후 수정(modify)할 수 있도록 하려면 구조체(structure) 자체를 변수(variable)로 선언(declare)해야 한다:
let fixedArea = DeliveryArea(center: storeLocation, radius: 4) // Error: Cannot assign to property fixedArea.radius = 3.5
radius
을var로
선언(declared)했지만, 이를 가지고 있는(enclosing type)fixedArea
이 상수(constant)이므로 변경(changed)할 수 없다. 컴파일러(compiler)가 올바르게(correctly) 오류(error)를 내보낸다(emits).fixedArea
를let
상수(constant)에서var
변수(variable)로 변경하여 이를 수정 가능(mutable)하도록 한다.이제 구조체(structure)에서 속성(properties)의 가변성(mutability)을 제어(control)하는 방법을 배웠다.
Mini-exercise
Location
과DeliveryArea
를 사용하도록isInDeliveryRange
를 다시 작성(rewrite)한다.Introducing methods
구조체(structures)의 일부 기능(capabilities)을 사용하여, 이제 다음과 같은 피자(pizza) 배달(delivery) 범위(range) 계산기(calculator)를 만들 수 있다:
let areas = [ DeliveryArea(center: Location(x: 3, y: 3), radius: 2.5), DeliveryArea(center: Location(x: 8, y: 8), radius: 2.5) ] func isInDeliveryRange(_ location: Location) -> Bool { for area in areas { let distanceToStore = distance(from: (area.center.x, area.center.y), to: (location.x, location.y)) if distanceToStore < area.radius { return true } } return false } let customerLocation1 = Location(x: 5, y: 5) let customerLocation2 = Location(x: 7, y: 7) isInDeliveryRange(customerLocation1) // false isInDeliveryRange(customerLocation2) // true
이 예(example)에는 배열(array),
areas
및 해당 배열(array)을 사용(uses)하여 고객(customer)의 위치(location)가 이러한 영역(areas) 내에 있는지 확인(determine)하는 함수(function)가 있다.범위(range) 안에 있다는 것은 특정(particular) 식당(restaurant)에 대해 알고 싶은 것이다.
DeliveryArea
에서 해당 식당(restaurant)이 특정 위치(location)로 배달(deliver) 가능 한지 알려줄 수 있다면 좋을(great) 것이다.구조체(structure)가 상수(constants)와 변수(variables)를 가질 수 있는 것과 마찬가지로, 자체(own) 함수(functions)를 정의(define)할 수도 있다. 플레이그라운드(playground)에서
DeliveryArea
의 구현(implementation) 부분을 찾는다. 닫는(closing) 중괄호(curly brace) 바로 앞에 다음 코드(code)를 추가한다:func contains(_ location: Location) -> Bool { let distanceFromCenter = distance(from: (center.x, center.y), to: (location.x, location.y)) return distanceFromCenter < radius }
이 코드(code)는 이제
DeliveryArea
의 구성 요소(member)인contains
함수(function)를 정의(defines)한다. 형식(types)의 구성 요소(members)인 함수(functions)를 메서드(methods)라고 한다.contains
은 현재(current) 위치(location)의center
와radius
속성(properties)을 사용한다. 구조체(structure) 내부(inside)의 속성(properties)과 기타 구성 요소(members)에 대한 이러한 암묵적(implicit) 접근(access)은 메서드(methods)를 일반(regular) 함수(functions)와 다르게 만든다. 12장(chapter), "Methods"에서 메서드(methods)에 대해 자세히 알아(learn)볼 것이다.구조체(structures)의 다른 구성 요소(members)와 마찬가지로, 점 구문(dot syntax)을 사용하여 메서드(method)에 접근(access)할 수 있다:
let area = DeliveryArea(center: Location(x: 8, y: 8), radius: 2.5) let customerLocation = Location(x: 7, y: 7) area.contains(customerLocation) // true
Mini-exercises
- x-y 튜플(tuples) 대신(instead of) 매개변수(parameters)로
Location
을 사용하도록distance(from:to:)
를 변경(change)한다. Location
을 사용하여 새로운distance(from:to:)
를 호출(call)하도록contains(_:)
를 변경(change)한다.DeliveryArea에
해당 영역(area)과 다른 영역의 중복(overlaps) 여부를 알려주는overlaps(with:)
메서드(method)를 추가(add)한다.
Structures as values
값(value)이라는 용어(term)는 Swift의 구조체(structures)에서 중요한 의미(important meaning)를 가지는데, 구조체(structures)가 값 유형(value types)을 생성(create)하기 때문이다.
값 유형(value type)은 할당(assignment) 시 인스턴스(instances)가 복사(copied)되는 유형(type)이다.
var a = 5 var b = a a // 5 b // 5 a = 10 a // 10 b // 5
이 할당 시 복사(copy-on-assignment) 동작(behavior)은
a
가b
에 할당(assigned)될 때,a
값(value)이b
에 복사(copied into)된다는 것을 의미(means)한다. 나중에a
값(value)을 변경(change)해도b
값(value)은 그대로 유지(stays)된다. 따라서=
를 "~와 같음(is equal to)"이 아니라 "할당(assign)"으로 읽는 것이 중요(important)하다.b = a
문(statement)은 "a
의 값을b
에 할당(assign the value of a to b)"으로 읽는다(read).Note: 동일성(equality) 여부를 계산(calculate)하려면
==
를 사용한다.2 + 2 == 4
. 이 표현식(expression)은 "2 + 2는 4와 같은가?"라는 질문(question)으로 읽는다(read).DeliveryArea
구조체(struct)에서의 해당 원칙(principle)은 다음과 같이 적용된다:var area1 = DeliveryArea(center: Location(x: 3, y: 3), radius: 2.5) var area2 = area1 area1.radius // 2.5 area2.radius // 2.5 area1.radius = 4 area1.radius // 4.0 area2.radius // 2.5
이전(previous) 예제(example)와 마찬가지로,
area2.radius
는area1.radius
에 설정(set)된 새로운 값(value)을 가지지 않는다(pick up). 이러한 단절(disconnection)은 구조체(structures) 작업에서 값 의미론(value semantics)을 보여준다(demonstrates).area2
에area1
값(value)을 할당(assign)하면, 이 값(value)의 정확한(exact) 복사본(copy)을 얻는다(gets).area1
과area2
는 여전히(still) 완전(completely) 독립적(independent)이다.값(value) 의미론(semantics)과 복사(copying) 덕분에(thanks to), 구조체(structures)는 안전하게(safe) 값(values)이 공유(shared)되고 다른 코드 조각(piece of code)에서 변경(changed)될 가능성(possibly)에 대해 걱정(worry)할 필요가 없다.
Structures everywhere
Location
구조체(struct)와 단순(simple)Int
가 동일 할당 시 복사(copy-on-assignment) 동작(behavior)을 공유(share)하는 방법을 살펴 보았다. 둘 다 값(value) 유형(types)이고 값 의미론(value semantics)를 가지고 있기 때문에 동작을 공유(share)한다.구조체(structures)가 값(values)을 나타내는(represent) 것을 알게 되었지만,
Int
는 정확히(exactly) 무엇일까? Swift 라이브러리(library)에서Int
의 정의(definition)를 보면 약간(bit) 놀랄(surprised)지도 모른다:struct Int : FixedWidthInteger, SignedInteger { // … }
Int
유형(type)도 구조체(structure)이다.Double
,String
,Bool
,Array
,Dictionary
와 같은 많은 표준(standard) Swift 유형(types)은 구조체(structures)이다. 이후(future) 장(chapters)에서 배우게(learn) 되겠지만, 구조체(structures)의 값 의미론(value semantics)은 이와 대조적인(counterparts) 참조(reference) 유형(type)과 다르게, 핵심 Swift 유형(types)을 나타내는(representing) 데 이상적이며 다른 이점(advantages)을 제공(provide)한다.Conforming to a protocol
위(above) Swift 표준(standard) 라이브러리(library)의
Int
정의(definition)에서 익숙하지 않은(unfamiliar) 부분(parts)을 발견(noticed)했을 수 있다.FixedWidthInteger
와SignedInteger
유형(types)은Int
선언(declaration) 바로 뒤(right after)에 나타난다(appear):struct Int : FixedWidthInteger, SignedInteger { // … }
이러한 유형(types)을 프로토콜(protocols)이라고 한다.
Int
가 선언(declared)될 때, 콜론(colon) 뒤에 두어(putting)Int
가 이러한 프로토콜(protocols)을 준수(conforms)한다는 신호(signal)를 보낸다.프로토콜(protocols)에는 준수 유형(conforming types)이 충족(satisfy)해야 하는(must) 일련의 요구 사항(set of requirements)이 포함(contain)되어 있다. 표준(standard) 라이브러리(library)에서의 간단한(simple) 예(example)는
CustomStringConvertible
이다:public protocol CustomStringConvertible { /// A textual representation of this instance. var description: String { get } }
이 프로토콜(protocol)에는 하나의 속성(property) 요구 사항(requirement)인
description
이 포함(contains)되어 있다. 설명(documentation)에는description
을 "이 인스턴스의 텍스트 표현(A textual representation of this instance)"이라고 한다.CustomStringConvertible
을 준수(conform)하도록DeliveryArea
를 수정(modify)하려면, 인스턴스(instance)의 "텍스트 표현(textual representation)"을 나타내는description
속성(property)을 추가(add)해야 한다. 지금 바로 해 본다(try this now).DeliveryArea
를 다음으로 변경(change)한다:struct DeliveryArea: CustomStringConvertible { let center: Location var radius: Double var description: String { """ Area with center: (x: \(center.x), y: \(center.y)), radius: \(radius) """ } func contains(_ location: Location) -> Bool { distance(from: center, to: location) < radius } func overlaps(with area: DeliveryArea) -> Bool { distance(from: center, to: area.center) <= (radius + area.radius) } }
description
속성(property)의 값(value)은 중심(center)과 현재(current) 반경(radius)을 포함(contains)한다. 다른 곳에서의 변경 사항(changes)에 대응(response)하여 업데이트(updates)되는 값(value)을 연산 속성(computed property)라고 한다.11장(chapter), "Properties"에서 연산 속성(computed properties)에 대해 자세히 배울 것이다.
그렇다면 프로토콜(protocol)을 준수(conforming)한다는 것은 정확히(exactly) 무엇을 하는 것일까?
CustomStringConvertible
을 준수(conforming to)하는 모든 유형(any type)은description
을 정의(define)해야 하므로,CustomStringConvertible
을 준수(conforms to)하는 모든 유형(any type)의 인스턴스(instance)에 대해description
을 호출(call)할 수 있다. Swift 표준(standard) 라이브러리(library)는 이것을print()
함수(function)에 활용한다(takes advantage of). 이 함수(function)는 콘솔(console)에서 다소 번잡한 기본(default) 설명(description) 대신(instead of)description
을 사용(use)한다:print(area1) // Area with center: (x: 3, y: 3), radius: 4.0 print(area2) // Area with center: (x: 3, y: 3), radius: 2.5
모든(any) 명명된 유형(named type)은 프로토콜(protocols)을 사용하여 동작(behavior)을 확장(extend)할 수 있다. 이 경우(in this case), Swift 표준(standard) 라이브러리(library)에 정의(defined)된 프로토콜(protocol)에 따라 구조체(structure)를 준수(conformed)해야 한다. 16장(chapter), "conformed"에서 프로토콜(protocols)의 정의(defining), 사용(using) 및 준수(conforming)에 대해 자세히 알아볼 것이다.
Challenges
다음 단계로 넘어가기 전에(before moving on) 구조체(structures)에 대한 지식(knowledge)을 확인(test)하기 위한 몇 가지 챌린지(challenges)가 있다. 스스로 해결(solve)해 보려고 하는 것이 가장 좋지만, 막힌다면(get stuck) 다운로드(download)나 책의 소스 코드 링크(source code link)에서 해답(solutions)을 참고할 수 있다.
Challenge 1: Fruit tree farm
과일 나무(fruit tree) 농장(farm)에서 배(pears), 사과(apples), 오렌지(oranges)와 같은 다양한 종류의(different kinds of) 과일(fruits)을 재배(grow)하고 있다고 상상해 본다(imagine). 과일(fruits)을 따고(picked) 나면, 중앙 시설(central facility)에서 처리(processed)하기 위해 트럭(truck)으로 가져간다. 트럭(truck)에서 과일(fruits)은 이 모두 함께 섞이기(mixed) 때문에, 중앙 시설(central facility)의 작업자(workers)는 올바른(correct) 재고(inventory) 컨테이너(container)에 하나씩(one by one) 과일을 분류(sort)해야 한다.
다양한 종류(different kinds of)의 과일(fruits)로 가득 찬 트럭(truck)을 받아, 각(each) 과일(fruit)을 올바른(correct) 재고(inventory) 컨테이너(container)에 담는 알고리즘(algorithm)을 구현(implement)한다.
시설(facility)에서 처리한(processed) 과일(fruit)의 총 중량(total weight)을 기록(track)하고, 재고(inventory)에 있는 각(each) 과일(fruit)의 수를 출력(print out)한다.
Challenge 2: A T-shirt model
크기(size), 색상(color), 재료(material) 선택 항목(options)이 있는 티셔츠(T-shirt) 구조체(structure)를 생성한다(create). 이 속성(attributes)에 따라(based on) 셔츠(shirt)의 비용(cost)을 계산(calculate)하는 메서드(method)을 제공(provide)한다.
Challenge 3: Battleship
Battleship과 같은 보드 게임을 위한 엔진(engine)을 작성(write)한다. Battleship에 익숙(familiar with)하지 않다면, 이 웹페이지(webpage)에서 자세한 내용(details)을 알아볼 수 있다: http://bit.ly/2nT3JBU
- 구조체(structure)를 사용하여, 모델링된 위치(locations modeled)에 대해 (x, y) 좌표(coordinate)를 사용한다.
- 선박(ships) 또한 구조체(structures)로 모델링(modeled with)되어야 한다. 원점(origin), 방향(direction) 및 길이(length)를 기록(record)한다.
- 각(each) 선박(ship)은 "shot"가 "hit"으로 이어졌는지(resulted in) 보고(report)할 수 있어야 한다.
Key points
- 구조체(structures)는 코드(code)에서 정의(define)하고 사용(use)할 수 있는 명명된 유형(named types)이다.
- 구조체(structures)는 값 유형(value types)이므로, 할당(assignment) 시 해당 값(values)이 복사(copied)된다.
- 점 구문(dot syntax)을 사용하여 구조체(structures)와 같은 명명된 유형(named types)의 구성 요소(members)에 접근(access)한다.
- 명명된 유형(named types)은 속성(properties) 및 메서드(methods)라고 하는 고유한(own) 변수(variables)와 함수(functions)를 가질 수 있다.
- 프로토콜(protocol)을 준수(conforming)하려면, 해당 프로토콜(protocol)에 필요한(required) 속성(properties)과 메서드(methods)를 구현(implementing)해야 한다.
'Raywenderlich > Swift Apprentice' 카테고리의 다른 글
Chapter 9: Strings (0) 2022.09.29 Chapter 8: Collection Iteration With Closures (0) 2022.08.29 Chapter 7: Arrays, Dictionaries & Sets (1) 2022.08.27 Chapter 6: Optionals (0) 2021.10.08 Chapter 5: Functions (0) 2021.09.02 - x-y 튜플(tuples) 대신(instead of) 매개변수(parameters)로