[Swift] Type & Mutation - 2
Defining a Point
이전 포스트를 참고하여 감안할 때 Point는 구조체가 적당한걸로 판단되어짐
구조체로 타입을 정하고 아래의 코드를 작성
struct Point: Equatable {
var x, y: Double
}
struct Size: Equatable {
var width, height: Double
}
struct Rectangle: Equtable {
var origin: Point
var size: Size
}
함수와 메서드 (Function And Methods)
위의 코드에서 Point, Size, Rectangle 타입 모두 저장 프로퍼티만 존재함
몇 가지 메소드를 추가해보자
extension Point {
func flipped() -> Self {
Point(x: self.y, y: self.x)
}
mutating func flip() {
let temp = self
self.x = temp.y
self.y = temp.x
}
}
flipped()와 flip() 모두 x, y 값을 교환하는 메소드이다.
차이점은 2가지가 있다
flipped()는Self를 반환하는 메서드flip()은 반환하지 않는 메서드flipped()는self를 참조로서만 사용하지만flip()은 참조도 하고 수정으로도 사용한다. 수정하기 때문에mutating키워드가 붙음
위 코드를 좀 더 이쁘게 수정할 수 있다
func flipped() -> Self {
Point(x: y, y: x)
}
mutating func flip() {
self = flipped()
}
불필요한 self의 참조가 사라지고
실제 x, y가 교환되는 메서드는 flipped()에서만 행해 진다
Mutating and Self
Swift 컴파일러는 타입 메서드를 사용하여 self: Self를 보이지 않는 파라미터로 전달한다.
self는 자신의 인스턴스를 참조하는 키워드이고Self는 자신의 타입이다.
mutating 메서드를 사용하면 Swift는 보이지 않는 self: inout Self를 전달한다
inout 키워드는 함수에 들어갈 때와 종료할 때 각각 복사본을 만든다
Static method 와 Static Property
정적 메서드와, 정적 프로퍼티도 추가해보자
extension Point {
static var zero: Point {
Point(x:0, y:0)
}
static func random(inRadius radius: Double) -> Point {
guard radius >= 0 else { return .zero }
let x = Double.random(-radius ... radius)
let maxY = (radius * radius - x * x).squareRoot()
let y = Double.random(-maxY ... maxY)
return Point(x: x, y: y)
}
}
열거형 (Enumerations)
Swift의 열거형은 유한한 상태의 집합을 모델링할 수 있는 강력한 값 타입이다
enum Quadrant: CaseIterable, Hashable {
case i, ii, iii, iv
init?(_ point: Point) {
guard !point.x.isZero && !point.y.isZero else { return nil }
switch (point.x.sign, point.y.sign) {
case (.plus, .plus):
self = .i
case (.minus, .plus):
self = .ii
case (.minus, .minus):
self = .iii
case (.plus, .minus):
self = .iv
}
}
}
이 열거형은 사분면에 대한 추상화를 만듬
CaseIterable을 통해 allCase 배열에 접근이 가능하고
Hashable을 통해 Set의 Element로 사용이 가능하거나 Dictionary의 key로 사용이 가능하다
옵셔널 이니셜라이저를 사용하면 사분면에 없는 경우는 실패 가능하게 만들 수 있다.
Quadrant(Point(x: 10, y: -3)) // .iv
Quadrant(.zero) // nil
연관 값 (Associated Values)
Swift의 열거형은 특정 사례와 연관시킬 수 있기 때문에 매우 강력하다
다음 코드를 보자
enum Shape {
case point(point: Point)
case segment(start: Point, end: Point)
case circle(center: Point, radius: Double)
case rectangle(Rectangle)
}
let pointShape = Shape.rectangle(rect: Rectangle(origin: .zero, size: Size(width: 50, height: 50)))
switch pointShape {
case .point(let point):
print(point)
case .segment(start: let sPoint, end: let ePoint):
print("start : \(sPoint) end: \(ePoint)")
case .circle(center: let center, radius: let radius):
print("circle center \(center) radius\(radius)")
case .rectangle(rect: let rect):
print("rectangle \(rect.origin) \(rect.size)")
}
정리
이번 포스트 까지 Class, Struct, Method, Enum 등에 대해 복습함
다음 포스트엔 Protocol, Generic에 대해 다시 복습
댓글남기기