简体   繁体   English

在Swift中将抽象类型转换为具体类型

[英]Convert Abstract Type to Concrete Type in Swift

I am trying to make Data Model for my app. 我正在尝试为我的应用制作数据模型。 here is the scenario: 这是场景:

my app has Customer Model which contains customer's info, and also contain his/her Payment Source. 我的应用程序具有“客户模型”,其中包含客户的信息,还包含他/她的“付款来源”。 the API gives me two kind of payment sources: card and bank account which they have completely different fields. API为我提供了两种付款方式: 银行帐户 ,它们具有完全不同的字段。

So, here is my problem, I want to have abstract type which is PaymentSource then within each PaymentSource have a function to return object casted to it's type. 所以,这是我的问题,我想要一个抽象类型,即PaymentSource,然后在每个PaymentSource中都有一个函数,用于返回转换为该类型的对象。 some how I am type erasure. 我如何进行类型擦除。

I needed to put my abstract type in a box and use it as Concrete type (AnyPaymentSource). 我需要将抽象类型放在一个盒子中,并将其用作具体类型(AnyPaymentSource)。

So, I've done as following: 因此,我已完成以下操作:

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> 
}

but Customer gives me error with following description: Customer通过以下说明给我错误:

Using 'PaymentSource' as a concrete type conforming to protocol 'PaymentSource' is not supported 不支持将“ PaymentSource”用作符合协议“ PaymentSource”的具体类型

where am I doing wrong? 我在哪里做错了?

Swift is statically typed language . Swift是静态类型的语言 That means the type of a variable must be known at compile time. 这意味着必须在编译时知道变量的类型。

When i was faced with this problem, i solved it something like this 当我遇到这个问题时,我解决了这样的问题

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
}

If what are you trying to achieve is what @Andrew Ashurov mentioned in his answer, there is no need to implement AnyPaymentSource . 如果您要实现的目标是@Andrew Ashurov在他的回答中提到的目标,则无需实现AnyPaymentSource As mentioned in Swift Protocols Documentation : Swift协议文档中所述

Protocols do not actually implement any functionality themselves. 协议本身实际上并未实现任何功能。 Nonetheless, any protocol you create will become a fully-fledged type for use in your code . 但是, 您创建的任何协议都将成为可 在您的代码中使用 的完整类型

Meaning that are already able to treat a protocol as a type . 意味着已经能够将协议视为类型

It might be: 有可能:

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?
}

Creating Customers: 创建客户:

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())

Note that in Customer struct, paymentSource property of type PaymentSource which means it can assigned as any type that conforms to PaymentSource protocol ( Card and BankAccount in your case). 请注意,在“ Customer结构中, PaymentSource类型的paymentSource属性意味着可以将其分配为符合PaymentSource协议的任何类型(在您的情况下为CardBankAccount )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM