swift - Swift:使具有相同“形状”的两种类型符合通用协议
问题描述
我有两种不同的类型,它们代表相同的数据,并且具有完全相同的“形状”。这两种不同的类型是代码生成的,我不得不处理它们。但是,我想让它们符合一个通用协议,以便我可以将这两种类型视为相同。这是一个例子:
假设这是我的两种代码生成类型,我一直坚持:
struct User1 {
var email: String
var name: Name
struct Name {
var givenName: String
var familyName: String
}
}
struct User2 {
var email: String
var name: Name
struct Name {
var givenName: String
var familyName: String
}
}
我希望能够互换使用这些类型,因此我创建了一些它们可以遵循的协议:
protocol NameRepresenting {
var givenName: String { get }
var familyName: String { get }
}
protocol UserRepresenting {
var email: String { get }
var name: NameRepresenting { get }
}
然后我试图让它们符合:
extension User1.Name: NameRepresenting {}
// Error: Type 'User1' does not conform to protocol 'UserRepresenting'
extension User1: UserRepresenting {}
extension User2.Name: NameRepresenting {}
// Error: Type 'User2' does not conform to protocol 'UserRepresenting'
extension User2: UserRepresenting {}
我希望上面的方法可以工作,但是编译失败并出现上面评论的错误。有什么优雅的方法可以让这两种类型符合一个通用协议,这样我就可以互换使用它们了吗?
解决方案
生成的结构的name
属性具有 type Name
,而不是NameRepresenting
协议要求的。Swift 尚不支持协变返回 :(
您可以做的是添加关联的类型要求:
protocol UserRepresenting {
associatedtype Name : NameRepresenting
var email: String { get }
var name: Name { get }
}
这要求conformers 具有符合NameRepresenting
并且是name
属性的类型的类型。
但是,既然它具有关联的类型要求,则不能UserRepresenting
用作变量/函数参数的类型。您只能在通用约束中使用它。因此,如果您有一个需要 a 的函数,则UserRepresenting
需要这样编写:
func someFunction<UserType: UserRepresenting>(user: UserType) {
}
如果您的某个类/结构需要存储 type 的属性UserRepresenting
,则您也需要使您的类/结构成为通用的:
class Foo<UserType: UserRepresenting> {
var someUser: UserType?
}
这可能适用于您的情况,也可能不适用于您的情况。如果没有,你可以写一个类型橡皮擦:
struct AnyUserRepresenting : UserRepresenting {
var email: String
var name: Name
struct Name : NameRepresenting {
var givenName: String
var familyName: String
}
init<UserType: UserRepresenting>(_ userRepresenting: UserType) {
self.name = Name(
givenName: userRepresenting.name.givenName,
familyName: userRepresenting.name.familyName)
self.email = userRepresenting.email
}
}
现在您可以将 any 转换UserRepresenting
为 this AnyUserRepresenting
,然后使用AnyUserRepresenting
。
推荐阅读
- excel - Excel 的 LEN() 函数对超过 20 个字符的数字返回 5
- python - 来自展平列类型系列或列表的数据框
- email - Jenkins - 扩展电子邮件通知 - 使用来自 jenkins 的用户列表填充默认配方
- graphql - 如何将父类型值作为参数传递给 GraphQL-Dotnet 中的子类型?
- python - 如何在仍然访问完整目录的同时返回目录的最后一部分?特金特
- oracle - 将数据 clob 到多个列中
- python - Pycharm“没有名为 REPORT.py 的模块”,但是它存在并且可以工作。但是之后
- linux - 从多个匹配项中识别重叠范围的最小值和最大值
- list - 飞镖中带有条件的列表长度
- sapui5 - 如何更改 ui5 中 smartFilterBar 的默认变体名称(即“标准”到“自定义”)?