Swift 泛型:如何将关联类型与泛型参数匹配
Swift generics: how to match associatedtype with generic parameter
我的应用程序中有一个对象(比如一个用户对象),我想将其发布(因为某些 UI 依赖于它)。由于 Liskov 替换原则,我不想将它作为 EnvironmentObject 传递,所以我决定制作一个包装器。像这样:
protocol HasUser: ObservableObject {
var user: String { get }
}
class HasUserWrapper: HasUser {
var user: String { userGetter() }
private let userGetter: () -> String
let objectWillChange: AnyPublisher<Void, Never>
init<UO: HasUser>(wrapping userObject: UO) {
self.objectWillChange = userObject
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
self.userGetter = { userObject.user }
}
}
extension HasUser {
func eraseToHasUserWrapper() -> HasUserWrapper {
HasUserWrapper(wrapping: self)
}
}
class ConcreteHasUser: HasUser {
@Published var user: String = "john"
}
struct UserView {
@ObservedObject var hasUser: HasUserWrapper = ConcreteHasUser().eraseToHasUserWrapper()
var body: some View {
Text(hasUser.user)
}
}
现在,我想让这个包装器通用。所以我开始了这样的事情:
protocol HasThing: ObservableObject {
associatedtype Thing
var thing: Thing { get }
}
class HasThingWrapper<Thing>: HasThing {
var thing: Thing { thingGetter() }
private let thingGetter: () -> Foo
let objectWillChange: AnyPublisher<Void, Never>
init<HasThingType: HasThing>(wrapping hasThing: HasThingType) {
self.objectWillChange = hasThing
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
self.thingGetter = { hasThing. }
}
}
extension HasThing {
func eraseToThingWrapper() -> HasThingWrapper<Thing> {
HasThingWrapper(wrapping: self)
}
}
protocol HasString: HasThing {
var thing: String { get }
}
class StringHolder: HasString {
@Published var thing: String = "hello"
}
如何告诉编译器包装器中的通用类型 Thing 应该与 HasThing 协议中的关联类型 Thing 匹配?
如果我没理解错的话,你只需要在 init
:
中添加一个泛型约束
init<HasThingType: HasThing>(wrapping hasThing: HasThingType)
where HasThingType.Thing == Thing
{
...
// then you can do:
self.thingGetter = { hasThing.thing }
}
我的应用程序中有一个对象(比如一个用户对象),我想将其发布(因为某些 UI 依赖于它)。由于 Liskov 替换原则,我不想将它作为 EnvironmentObject 传递,所以我决定制作一个包装器。像这样:
protocol HasUser: ObservableObject {
var user: String { get }
}
class HasUserWrapper: HasUser {
var user: String { userGetter() }
private let userGetter: () -> String
let objectWillChange: AnyPublisher<Void, Never>
init<UO: HasUser>(wrapping userObject: UO) {
self.objectWillChange = userObject
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
self.userGetter = { userObject.user }
}
}
extension HasUser {
func eraseToHasUserWrapper() -> HasUserWrapper {
HasUserWrapper(wrapping: self)
}
}
class ConcreteHasUser: HasUser {
@Published var user: String = "john"
}
struct UserView {
@ObservedObject var hasUser: HasUserWrapper = ConcreteHasUser().eraseToHasUserWrapper()
var body: some View {
Text(hasUser.user)
}
}
现在,我想让这个包装器通用。所以我开始了这样的事情:
protocol HasThing: ObservableObject {
associatedtype Thing
var thing: Thing { get }
}
class HasThingWrapper<Thing>: HasThing {
var thing: Thing { thingGetter() }
private let thingGetter: () -> Foo
let objectWillChange: AnyPublisher<Void, Never>
init<HasThingType: HasThing>(wrapping hasThing: HasThingType) {
self.objectWillChange = hasThing
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
self.thingGetter = { hasThing. }
}
}
extension HasThing {
func eraseToThingWrapper() -> HasThingWrapper<Thing> {
HasThingWrapper(wrapping: self)
}
}
protocol HasString: HasThing {
var thing: String { get }
}
class StringHolder: HasString {
@Published var thing: String = "hello"
}
如何告诉编译器包装器中的通用类型 Thing 应该与 HasThing 协议中的关联类型 Thing 匹配?
如果我没理解错的话,你只需要在 init
:
init<HasThingType: HasThing>(wrapping hasThing: HasThingType)
where HasThingType.Thing == Thing
{
...
// then you can do:
self.thingGetter = { hasThing.thing }
}