문제의 역사:
Shadowing(섀도잉)은 동일한 이름을 가진 변수가 내부 가시성 범위에서 선언되어 외부 변수의 이름을 가리는 현상입니다. 초기 스위프트 버전에서는 컴파일러가 섀도잉에 대해 엄격하지 않았지만, 언어 모델이 복잡해짐에 따라 이러한 경우를 명확히 식별하는 것이 필수적이 되었습니다. 이는 버그를 피하기 위해서입니다.
문제점:
섀도잉은 코드 유지 보수를 어렵게 하고 추적하기 힘든 오류를 발생시킵니다. 동일한 이름의 변수를 우연히 선언하게 되면 개발자가 예상하는 변수가 아닌 다른 변수에 접근하게 될 수 있습니다. 특히, 변수를 참조로 전달하는 경우나 반복문 또는 클로저 안에서는 이러한 오류가 실행 단계에서만 드러나는 경우가 많습니다.
해결책:
스위프트는 변수의 섀도잉을 허용하지만 중요한 변수/속성을 가리는 경우를 피하고 서로 다른 이름을 사용하거나 명시적인 self/this 참조를 사용하는 것이 권장됩니다. 특히 구조체(struct)나 클래스(class)의 초기화자에서 self를 사용하여 멤버와 매개변수를 구분하는 것이 좋습니다:
코드 예시:
struct User { let name: String init(name: String) { self.name = name // self는 할당의 명확성을 보장합니다. } }
주요 특징:
반복문과 클로저에서 섀도잉이 발생하면 어떤 일이 일어날까요?
클로저 내에서 외부 컨텍스트와 동일한 이름의 변수를 선언하면, 외부 변수가 숨겨지게 됩니다. 이로 인해 예기치 않은 동작이 발생할 수 있으며, 특히 멀티스레딩 상황에서 더욱 그렇습니다.
let value = 10 let closure = { let value = 20; print(value) } closure() // 20 print(value) // 10
하나의 범위 내에서 동일한 이름으로 상수와 변수를 선언할 수 있나요?
아니요. 스위프트에서는 동일한 범위 내에 var와 let을 같은 이름으로 둘 수 없습니다:
let x = 5 var x = 10 // 오류: 'x'의 잘못된 재선언
상속 시 클래스 속성의 섀도잉으로 인한 혼란을 피하는 방법은 무엇인가요?
하위 클래스가 부모 클래스와 동일한 이름의 속성을 선언하면 섀도잉이 발생합니다. 그러나 super 또는 self를 통한 접근 시 해당 속성이 선택됩니다. 필요 없이 동일한 이름을 사용하는 것은 피하는 것이 좋습니다.
클래스 Account에서 한 개발자가 함수의 매개변수 이름으로 balance를 우연히 사용하고, 함수 내에서 다시 let balance = ...로 사용했습니다. 섀도잉 때문에 잘못된 값으로 계산이 수행되었고, 함수는 잘못된 결과를 반환했으며, 이는 테스트의 후기 단계에서만 밝혀졌습니다.
장점:
단점:
팀 전체가 접두사를 사용(예: inputBalance)하거나 항상 self를 사용하여 속성에 대한 참조를 사용하기로 합의했습니다. 그 결과, 섀도잉으로 인한 오류가 거의 사라졌고 코드 유지 보수가 용이해졌습니다.
장점:
단점: