[Swift] protocol 함수 선언에서 매개변수 기본값을 사용할 수 있을까?

이정훈·2025년 3월 24일
0

Swift 파헤치기

목록 보기
11/12
post-thumbnail

protocol 함수 선언에서 매개변수 기본값

우리는 함수의 매개변수에 기본값이라는 것을 사용한다. 왜냐하면 어쩌다 한번 바뀌는 값을 위해 항상 매개변수로 인자 값을 전달하기 번거롭기 때문이다. protocol을 사용하면서 protocol 함수 선언에 매개변수 기본값을 사용하는 경우 아래와 같은 에러를 마주하게 된다.

protocol SomeProtocol {
    func doSomething(_ message: String = "Hellow World!")    // ⛔️ Default argument not permitted in a protocol method
}

결론부터 말하면 protocol 함수 선언부에 매개변수 기본값을 사용할 수 없다.

그럼 매개변수 기본값 어떻게 사용해야 할까?

당연하게도 protocol을 사용하지 않고 구체적인 타입만을 사용하면 매개변수 기본값을 사용할 수 있다.

struct SomeItem {
    func doSomething(_ message: String = "Hello World!") {
        print(message)
    }
}

let s = SomeItem()
s.doSomething()    // "Hello World!"

하지만 이 방법도 썩 내키지는 않는다. 왜냐하면 누구나 마음속 한쪽에 자리잡고 있는 밥 아저씨의 DIP 원칙에 따라 구체적인 타입보단 추상적인 타입에 의존해야 한다는 원칙을 지키고자 하기 때문이다.

정말 방법이 없는 것일까?

위에서 말했듯이 Swift에서 protocol 선언부에 매개변수 기본값은 사용할 수 없다. 하지만 protocolextension을 결합한다면, protocol에서 기본값을 사용한 것과 같은 효과를 구현할 수 있다.

protocol SomeProtocol {
    func doSomething(_ message: String)
}

extension SomeProtocol {
    func doSomething(_ message: String = "Hello") {
        print(message)
    }
}

struct SomeItem: SomeProtocol {}

let s: SomeProtocol = SomeItem()
s.doSomething()    // "Hello"

기존 protocol 선언부는 그대로 놔두고, extension을 통해 기본 메서드를 구현하면 된다. 이제 우리는 DIP 원칙도 만족하면서 protocol에서 매개변수 기본값을 가진 메서드처럼 사용할 수 있게 되었다.

만족. 😀

🤔 조금 더 나아가자

이번에는 protocol을 채택하는 타입에 따라 서로 다른 메서드의 구현부가 필요한 상황을 가정하고 아래의 코드를 살펴보자.

protocol SomeProtocol {
    func doSomething(_ message: String)
}

extension SomeProtocol {
    func doSomething(_ message: String = "Hello") {
        print(message)
    }
}

struct SomeItem: SomeProtocol {
    func doSomething(_ message: String) {
        print("\(message) Swift!")
    }
}

let s: SomeProtocol = SomeItem()
s.doSomething()    // "Hello"

기본적으로 Swift에서 protocolextension을 결합하여 메서드를 기본 구현하고, protocol를 채택한 구체 타입에서도 동일한 메서드를 직접 구현했다면, 구체화된 타입에 직접 구현된 메서드가 호출하게 된다. 하지만 s의 타입이 protocol 타입으로 선언 되어 있고, 매개변수 기본값을 사용하는 경우 protocolextension에서 구현된 코드가 실행되는 것을 확인할 수 있었다.

이것은 아래와 같이 변수 s가 구체적인 타입으로 선언되어 있어도 동일한 결과를 가져왔다.

let s: SomeItem = SomeItem()
s.doSomething()    // "Hello"

그렇다면 매개변수 기본값을 사용하면서, 구체적인 타입에서 직접 구현한 코드를 실행하려면 어떻게 해야할까?
아래의 코드와 같이 extension 메서드 구현 내부에서 doSomething(_:)을 다시 호출하면 protocol을 채택한 구체 타입의 구현부가 호출된다.

protocol SomeProtocol {
    func doSomething(_ message: String)
}

extension SomeProtocol {
    func doSomething(_ message: String = "Hello") {
        doSomething(message)
    }
}

struct SomeItem: SomeProtocol {
    func doSomething(_ message: String) {
        print("\(message) Swift!")
    }
}

let s: SomeProtocol = SomeItem()
s.doSomething()    // "Hello Swift!"
profile
새롭게 알게된 것을 기록하는 공간

0개의 댓글