티스토리 뷰

반응형

 

안녕하세요 :) Zedd입니다.

Swift 5.7 이어서~~~

 

다음과 같은 간단한 Generic 메소드를 봅시다. 

func compute<C: Collection>(_ values: C) -> Int {
    return values.count
}

Collection protocol을 conform하고있는 generic parameter를 받도록 되어있습니다. 

func compute<C: Collection>(_ values: C) -> Int {
    return values.count
}

compute([1, 2, 3]) // 3
compute(["Zedd": "안녕"]) // 1

그래서 Array나 Dictionary같은 Collection 들을 넣을 수 있게 됩니다.

 

# default value expression with a generic parameter

일반 메소드 parameter에 default value를 넣을 수 있듯이,

generic parameter에도 default value를 넣어보고싶지만..

func compute<C: Collection>(_ values: C = ✅[1, 2, 3]✅) -> Int {
    return values.count
}
// 🚫 Default argument value of type '[Int]' cannot be converted to type 'C'

컴파일 에러가 나는데요. 현재 semantic rule상 안된다고 함;;

그래서 SE-0347 에서는

call site에서 명시적으로 파라미터를 안줬을 때 default value로 넣어둔 concrete type에 대해 타입 추론을 허용하자!


를 제안합니다.

 

Swift 5.7에서는 

func compute<C: Collection>(_ values: C = [1, 2, 3]) -> Int {
    return values.count
}

compute([1, 2, 3]) // 3
compute(["Zedd": "안녕"]) // 1
compute() // 3 ✅

위와같이 call site에서 명시적으로 파라미터를 안줬을 때 default value로 넣어둔 [1, 2, 3]으로 타입 추론을 한다는 것이죠.

 

하지만 아묻따 generic parameter에 default value를 넣을 수 있는 것은 아니고,

여전히 컴파일에러가 나는 상황이 있는데요.

func compute<T, U: Collection>(value: T = 42,
                               collection: U) where U.Element == T {

}
// 🚫 Cannot use default expression for inference of 'T' because requirement 'T == U.Element' refers to other generic parameters

위와 같은 상황에서 여전히 

자 위에 T에 42라는 default value를 줬죠?

이러한 default parameter와 관련하여 암시적 or 명시적으로 call site에서 타입을 유추할 수 있다면

concrete type으로 입력된 default value는 여전히 컴파일 에러가 납니다. 

 

여기서는 U.Element = T라는 요구조건이 있고 여기서 T의 타입을 유추할 수 있기 때문에 컴파일 에러가 나는 것이죠. 

func compute<T, U: Collection>(value: T = 42,
                               collection: U = []) where U.Element == Int {

} ✅

만약 이렇게 T와 U가 서로 독립적으로 있다면 T의 default value가 허용됩니다. 

 

또 하나 허용 안되는 경우를 볼까요

 Swift 공식문서 - Generic 파트에 있는 메소드입니다. 

func findIndex<T: Equatable>(of valueToFind: T, in array: [T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

여기서 파라미터에 default value를 넣으면 잘 될 것 같지만, 

func findIndex<T: Equatable>(of valueToFind: T = 42 ✅, in array: [T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}
// 🚫 cannot use default expression for inference of 'T' because it is inferrable from parameters #0, #1

 

컴파일 에러가 나게 됩니다. 

첫번째, 두번째 파라미터로 (암시적 or 명시적으로) T를 유추할 수 있기 때문에.. default value를 넣어줄 수 없습니다.



ㅁ.....

 

Swift Generic이 runtime에 타입이 결정되는데, 

func compute<C: Collection>(_ values: C = [1, 2, 3]) -> Int {
    return values.count
}

compute([1, 2, 3]) // 3
compute(["Zedd": "안녕"]) // 1
compute() // 3 ✅

위와 같을 때는 아직 타입을 유추할 수 없고...

func findIndex<T: Equatable>(of valueToFind: T = 42 ✅, in array: [T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}
// 🚫 cannot use default expression for inference of 'T' because it is inferrable from parameters #0, #1

이때는 call site에서 T를 유추할 수 있기 때문에.. (첫번째, 두번째 파라미터에 같은 타입을 넣어줘야하니까..) 안되는 것 같네요.

 

틀린 부분이 있으면 댓글 남겨주세요!

요거 왜 안되는지, 되는지 잘 이해가 안가서 ㅎㅎ;; 계속 봤네요.

 

[참고]

- SE-0347

반응형