【问题标题】:Unable to create sender/receiver protocols无法创建发送方/接收方协议
【发布时间】:2021-12-26 01:46:55
【问题描述】:

我有 2 个这样的协议:

protocol Receiver {
    associatedtype Input
    
    func send(_ input: Input)
}
protocol Sender {
    associatedtype Output
    
    init<T: Receiver>(_ receiver: T) where T.Input == Output
}

为了实现Sender,我首先这样做:

class TestSender: Sender {
    typealias Output = String
    
    required init<T: Receiver>(_ receiver: T) where T.Input == Output {
        
    }
}

但是,我需要将来自 initreceiver 存储为类属性。由于Receiver 有关联的类型要求,我必须为整个TestSender 类添加一个泛型类型约束,如下所示:

class TestSender<T: Receiver>: Sender where T.Input == String

然后我可以像这样在TestSender 中声明一个属性:

private let receiver: T

但在初始化程序中,我不能分配receiver

required init<T: Receiver>(_ receiver: T) where T.Input == Output {
    self.receiver = receiver // Cannot assign value of type 'T' to type 'T'
}

我尝试改变init方法如下:

init(_ receiver: T) {
    self.receiver = receiver
}

但是现在,Swift 编译器说我没有正确地遵守协议。这样做的正确方法是什么?

【问题讨论】:

    标签: swift generics


    【解决方案1】:

    解决方案

    您可以使ReceiverSender 协议上具有associatedtype,以便Sender 在其Receiver 之上是通用的。

    代码:

    protocol Sender {
        associatedtype InputReceiver: Receiver
        associatedtype Output = InputReceiver.Input
    
        init(_ receiver: InputReceiver)
    }
    
    class TestSender<T: Receiver>: Sender {
        typealias Output = String
    
        private let receiver: T
    
        required init(_ receiver: T) {
            self.receiver = receiver
        }
    }
    

    为什么原始代码不起作用?

    使用您的最新代码,您应该会看到以下错误:

    类型“TestSender”不符合协议“Sender”

    这表明某些要求未得到满足。如果单击 fix-it,则表明初始化程序存在问题。如果你再次点击 fix-it,你又回到了以下问题:

    无法将类型“T”的值分配给类型“T”

    这是因为您在TestSender 上有一个通用的T 并且在初始化程序上还有一个通用的T。这些是不同的类型。

    但是,忽略这一点,问题的根源在于:在您的 Sender 协议中,您只有在 initializer 上有一个泛型,而在您正在尝试的 TestSender 类中在类本身上创建一个泛型。

    要使一个协议“通用”,你给它一个associatedtype。并且由于 Receiver 是通用的东西,它被用来创建一个 associatedtype

    因为我们有Receiver 泛型,所以我们也可以在Sender 中获得Output 类型。

    我希望这是有道理的,如果您有任何问题,请询问(这很难解释!)

    【讨论】:

    • 感谢您的回答!这很好,但我很好奇为什么原始代码没有?
    • 关于乔治的回答要注意的关键是您的错误在于使init 本身具有通用性。您不能这样做,因为通用占位符类型不会“泄漏”init 以使 receiver 成为该类型。 TestSender 类 本身 需要在 Receiver 约束类型上是通用的。
    • @SeedApple 我添加了更多解释,希望对您有所帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多