📱 iOS/Swift
[Swift] indirect enum 문법
kyxxn
2024. 7. 17. 17:31
문제상황
'<P><IMG SRC="camp.jpg">camp</IMG></P>' 와 같은 XML 태그가 주어지면,
이를 Parser 할 때, P 태그 자식인 IMG 태그는 Token을 어떻게 분류하고 관리할까 ?
struct로 관리하면 자신을 참조할 수 없어 문제가 생긴다. 물론, class를 써도 된다.
그러나 class를 쓰지 않고, 재귀적인 방법을 찾아보다가 indirect enum 문법을 발견했다.
indirect enum의 개념
- Swift의 열거형(enum)에서 재귀적인 데이터 구조를 표현할 수 있도록 해주는 문법
- 열거형의 케이스가 자기 자신을 포함할 수 있게 만들어서
재귀적으로 중첩된 데이터 구조를 명확하고 간결하게 정의
언제, 왜 사용할까 ?
일반적으로 열거형은 값 타임임
값 타임은 그 크기를 컴파일 때 알 수 있어야 하는데,
재귀적 구조를 사용하면 자기 자신을 포함하는 구조체 || 열거형은 크기 결정이 안된다.
indriect 키워드를 통해 이런 제한을 우회하여 간접적으로 자기 자신을 참조
indirect enum 사용하기
1번 방법: 열거형 전체를 indirect로
: 열거형의 모든 케이스가 재귀적인 구조를 가짐
indirect enum Element {
case element(tagName: String, attributes: [String: String]?, subTags: [Element]?)
case content(String?)
}
2번 방법: 특정 케이스만 indirect로 정의
: 특정 케이스에만 재귀적인 구조를 허용함
enum Element {
indirect case element(tagName: String, attributes: [String: String]?, subTags: [Element]?)
case content(String?)
}
실습
// <P><IMG SRC="camp.jpg">camp</IMG></P>
indirect enum Element {
case element(tagName: String, attributes: [String: String]?, subTags: [Element]?)
case content(String?)
}
let imgElement = Element.element(tagName: "IMG", attributes: ["SRC": "camp.jpg"], subTags: nil)
let pElement = Element.element(tagName: "P", attributes: nil, subTags: [
imgElement,
.content("camp")
])
func printElement(_ element: Element, indent: String = "") {
switch element {
case let .element(tagName, attributes, subTags):
let attrString = attributes?.map { "\($0.key)=\"\($0.value)\"" }.joined(separator: " ") ?? ""
print("\(indent)<\(tagName) \(attrString)>")
if let subTags = subTags {
for child in subTags {
printElement(child, indent: indent + " ")
}
}
print("\(indent)</\(tagName)>")
case let .content(content):
print("\(indent)\(content ?? "")")
}
}
printElement(pElement)
camp