[Swift] Opaque Result Type을 사용하여 Genesic형 매개변수를 숨깁니다!
추기
더 좋은 방법이 생겼다.
정황
프로그램 라이브러리를 제작할 때 자주 다음과 같은 상황을 만날 수 있다.
public protocol MyPublicProtocol: Equatable {
init()
var number: Int { get }
}
// 何らかの値
public struct MyValue: MyPublicProtocol {
public init() {}
public let number: Int = 46
}
public struct MyPublicStruct<T: MyPublicProtocol> {
private var value: T
func isEqual(to value: T) -> Bool {
return value == self.value
}
}
MyPublicStruct
는 사용자도 사용하기를 원하는 구조체다.따라서 이것public
은 문제없다.문제는
MyValue
입니다.이는 사실 이용자가'몰라도 된다'는 것으로, 이용자가 이용하지 못하게 하려는 것이다.그러나 사용자들이 이걸 사용할 수 있도록 하기 위해서는 다음과 같은 명칭이 없어서는 안 된다.본의는 아니지만
MyValue
을 public
로 바꿀 필요가 있다.// 別のモジュールで初期化する処理
let instance = MyPublicStruct<MyValue>()
어떤 상황입니까?예를 들어
JapaneseKeyboardInputManager<T: InputStyleData>
가'일본어 키보드 입력 관리 유형'이라고 가정하고 InputStyleData
를 따르는 것은KanaInputStyleData
RomanInputStyleData
KanaInputStyleData
와 RomanInputStyleData
모두 실크로 돼 있어 외부에 공개하고 싶지 않다.근데 그걸 관리하는'일본어 키보드 입력 관리 유형'은 공개하고 싶어요.하고 싶은 일
어떻게든 숨기고 싶어
MyValue
.숨겨진다면 Opaque Result Type입니다.그걸로 하면 괜찮을 것 같은데.가장 좋은 방법은 다음과 같다
typealias
.그러나 이런 문장은 없고, 지금도 이런 문장이 이미 예정되어 있다는 것을 들어 본 적이 없다.// 利用者にはMyPublicStructForUserがMyPublicStruct<some MyPublicProtocol>に見えて欲しい
typealias MyPublicStructForUser = MyPublicStruct<MyValue> as MyPublicStruct<some MyPublicProtocol>
이건 못해도 아래처럼 쓰면 괜찮아.이 방법은 외부MyPublicStructFactory.instance()
를 통해 초기화되고MyValue
숨길 수 있습니다.public enum MyPublicStructFactory {
// 'some' types are only implemented for the declared type of properties and subscripts and the return type of functions
static func instance() -> MyPublicStruct<some MyPublicProtocol> {
return MyPublicStruct<MyValue>(value: .init())
}
}
그런데 이것도 불가능해요.오류 메시지와 같이 반환 값에는 유형 매개변수로 Opaque Result Type을 사용할 수 없습니다.이것은 Opaque Result Type이 현재 적용하고 있는 제한이며 향후 실현될 수 있습니다.위쪽
typealias
보다 희망이 있는 것 같아요.근데 그 전에 꼭 기다려야 돼요?해결하다
그럴 필요 없어.실현하는 방법을 조금만 바꾸면 이것이 가능하다.
public protocol MyPublicStructProtocol {
associatedtype T: MyPublicProtocol
func isEqual(to value: T) -> Bool
}
private struct MyPublicStruct<T: MyPublicProtocol>: MyPublicStructProtocol {
private var value: T
func isEqual(to value: T) -> Bool {
return value == self.value
}
}
private struct MyValue: MyPublicProtocol {
let number: Int = 46
}
public enum MyPublicStructFactory {
static func instance() -> some MyPublicStructProtocol {
return MyPublicStruct<MyValue>(value: .init())
}
}
최종 사용자가 얻은 것은 some MyPublicStructProtocol
의 유형이다.이렇게 되면 아무것도 하지 않은 것처럼 보이지만 MyPublicStructProtocol
public
에 올려놓을 것을 약속했기 때문에 이 사용에는 아무런 장애가 없다.또 대외적으로 공개된 것은 오파케형에 불과하기 때문에MyPublicStruct
와MyValue
모두 공개할 필요가 없으며value
에 대해서는 원래 진입protocol
에 대한 요구가 없기 때문에 외부에서 방문할 수 없다.실제로 사용자들은 어떻게 운영하고 있을까.언뜻 보기에는 불가사의한 일이지만 곤란한 것은 없다.
let instance = MyPublicStructFactory.instance()
let isEqual = instance.isEqual(to: .init())
let isEqualFunction = instance.isEqual
instance
는 some MyPublicStructProtocol
유형의 값이다.isEqual
문제 없는 호칭.흥미로운 것은
isEqual
라고 부르려면 점부호로만 불러야 한다.init()
.T
숨겨져 있기 때문에 이용자는 그것이 어떤 유형인지 알 수 없다.그럼에도 불구하고 MyPublicProtocol
알파벳 발생기의 존재를 약속했기 때문에 점 기호를 통해서만 초기화할 수 있다.시험해 보면
isEqualFunction
그 뜻을 알 수 있다.이것은 ((some MyPublicStructProtocol).T) -> Bool
유형의 함수다.위에서 확인한 바와 같이 숨겨진 파라미터의 제니릭형을 순조롭게 얻을 수 있습니다.다만, 당초 목적
MyPublicStruct
이 공개됐으면 좋았을 텐데 이 방법이 숨겨져'과도한 실복 은폐'상황으로 변해 다소 달갑지 않다.더 좋은 방법이 있다면 꼭 알려주세요!
Reference
이 문제에 관하여([Swift] Opaque Result Type을 사용하여 Genesic형 매개변수를 숨깁니다!), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/en3_hcl/articles/452655a7b743c0텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)