在 Swift 中将抽象类型转换为具体类型
Convert Abstract Type to Concrete Type in Swift
我正在尝试为我的应用制作数据模型。这是场景:
我的应用有包含客户信息的客户模型,还包含 his/her 付款来源。 API 给了我两种支付方式:card 和 bank account 它们有完全不同的字段。
所以,这是我的问题,我想要抽象类型,即 PaymentSource,然后在每个 PaymentSource 中都有一个函数将 return 对象转换为它的类型。一些我是如何类型擦除的。
我需要将我的抽象类型放在一个框中并将其用作具体类型 (AnyPaymentSource)。
所以,我做了如下操作:
protocol PaymentSource {
associatedtype Kind
func cast() -> Kind
}
struct AnyPaymentSource<PS: PaymentSource> {
private var paymentSource: PS
init(paymentSource: PS) {
self.paymentSource = paymentSource
}
func cast() -> PS.Kind {
return paymentSource.cast()
}
}
struct Card: PaymentSource {
func cast() -> Card {
return self
}
}
struct BankAccount: PaymentSource {
func cast() -> BankAccount {
return self
}
}
struct Customer {
var firstName: String
var lastName: String
var email: String
var paymentSource : AnyPaymentSource<PaymentSource>
}
但是 Customer
给我错误的描述如下:
Using 'PaymentSource' as a concrete type conforming to protocol 'PaymentSource' is not supported
我哪里做错了?
Swift 是 statically typed language。这意味着必须在编译时知道变量的类型。
当我遇到这个问题时,我是这样解决的
protocol PaymentSource {
associatedtype Kind
func cast() -> Kind
}
struct AnyPaymentSource<PS: PaymentSource> {
private var paymentSource: PS
init(paymentSource: PS) {
self.paymentSource = paymentSource
}
func cast() -> PS.Kind {
return paymentSource.cast()
}
}
struct Card: PaymentSource {
func cast() -> Card {
return self
}
}
struct BankAccount: PaymentSource {
func cast() -> BankAccount {
return self
}
}
struct Customer<T:PaymentSource> {
var firstName: String
var lastName: String
var email: String
var paymentSource : AnyPaymentSource<T>
}
func test(){
let customerWithCard = Customer<Card>(
firstName: "",
lastName: "",
email: "",
paymentSource: AnyPaymentSource(paymentSource: Card())
)
let customerWithBankAccount = Customer<BankAccount>(
firstName: "",
lastName: "",
email: "",
paymentSource: AnyPaymentSource(paymentSource: BankAccount())
)
print(customerWithCard.paymentSource.cast())
print(customerWithBankAccount.paymentSource.cast())
return
}
如果您要实现的是@Andrew Ashurov 在他的回答中提到的,则无需实现AnyPaymentSource
。如Swift Protocols Documentation所述:
Protocols do not actually implement any functionality themselves.
Nonetheless, any protocol you create will become a fully-fledged type
for use in your code.
意味着已经能够将协议视为类型。
可能是:
protocol PaymentSource {
func cast() -> Self
}
struct Card: PaymentSource {
func cast() -> Card {
return self
}
}
struct BankAccount: PaymentSource {
func cast() -> BankAccount {
return self
}
}
struct Customer {
var firstName: String
var lastName: String
var email: String
var paymentSource : PaymentSource?
}
创建客户:
let cardCustomer = Customer(firstName: "Card Fname", lastName: "Card Lname", email: "cardemail@example.com", paymentSource: Card())
let bankAccountCustomer = Customer(firstName: "Bank Account Fname", lastName: "Bank Account Lname", email: "bankaccountemail@example.com", paymentSource: BankAccount())
请注意,在 Customer
结构中,paymentSource
属性 类型 PaymentSource
这意味着它可以分配为任何符合 PaymentSource
协议的类型( Card
和 BankAccount
在你的情况下)。
我正在尝试为我的应用制作数据模型。这是场景:
我的应用有包含客户信息的客户模型,还包含 his/her 付款来源。 API 给了我两种支付方式:card 和 bank account 它们有完全不同的字段。
所以,这是我的问题,我想要抽象类型,即 PaymentSource,然后在每个 PaymentSource 中都有一个函数将 return 对象转换为它的类型。一些我是如何类型擦除的。
我需要将我的抽象类型放在一个框中并将其用作具体类型 (AnyPaymentSource)。
所以,我做了如下操作:
protocol PaymentSource {
associatedtype Kind
func cast() -> Kind
}
struct AnyPaymentSource<PS: PaymentSource> {
private var paymentSource: PS
init(paymentSource: PS) {
self.paymentSource = paymentSource
}
func cast() -> PS.Kind {
return paymentSource.cast()
}
}
struct Card: PaymentSource {
func cast() -> Card {
return self
}
}
struct BankAccount: PaymentSource {
func cast() -> BankAccount {
return self
}
}
struct Customer {
var firstName: String
var lastName: String
var email: String
var paymentSource : AnyPaymentSource<PaymentSource>
}
但是 Customer
给我错误的描述如下:
Using 'PaymentSource' as a concrete type conforming to protocol 'PaymentSource' is not supported
我哪里做错了?
Swift 是 statically typed language。这意味着必须在编译时知道变量的类型。
当我遇到这个问题时,我是这样解决的
protocol PaymentSource {
associatedtype Kind
func cast() -> Kind
}
struct AnyPaymentSource<PS: PaymentSource> {
private var paymentSource: PS
init(paymentSource: PS) {
self.paymentSource = paymentSource
}
func cast() -> PS.Kind {
return paymentSource.cast()
}
}
struct Card: PaymentSource {
func cast() -> Card {
return self
}
}
struct BankAccount: PaymentSource {
func cast() -> BankAccount {
return self
}
}
struct Customer<T:PaymentSource> {
var firstName: String
var lastName: String
var email: String
var paymentSource : AnyPaymentSource<T>
}
func test(){
let customerWithCard = Customer<Card>(
firstName: "",
lastName: "",
email: "",
paymentSource: AnyPaymentSource(paymentSource: Card())
)
let customerWithBankAccount = Customer<BankAccount>(
firstName: "",
lastName: "",
email: "",
paymentSource: AnyPaymentSource(paymentSource: BankAccount())
)
print(customerWithCard.paymentSource.cast())
print(customerWithBankAccount.paymentSource.cast())
return
}
如果您要实现的是@Andrew Ashurov 在他的回答中提到的,则无需实现AnyPaymentSource
。如Swift Protocols Documentation所述:
Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code.
意味着已经能够将协议视为类型。
可能是:
protocol PaymentSource {
func cast() -> Self
}
struct Card: PaymentSource {
func cast() -> Card {
return self
}
}
struct BankAccount: PaymentSource {
func cast() -> BankAccount {
return self
}
}
struct Customer {
var firstName: String
var lastName: String
var email: String
var paymentSource : PaymentSource?
}
创建客户:
let cardCustomer = Customer(firstName: "Card Fname", lastName: "Card Lname", email: "cardemail@example.com", paymentSource: Card())
let bankAccountCustomer = Customer(firstName: "Bank Account Fname", lastName: "Bank Account Lname", email: "bankaccountemail@example.com", paymentSource: BankAccount())
请注意,在 Customer
结构中,paymentSource
属性 类型 PaymentSource
这意味着它可以分配为任何符合 PaymentSource
协议的类型( Card
和 BankAccount
在你的情况下)。