实现获取并返回Self的协议静态方法(在swift中)

时间:2017-09-22 16:02:20

标签: swift generics swift-protocols

根据这些方针给出协议:

$this->load->library("bcrypt");

如何实现盒子类?

application/models/User.php

编译器抱怨protocol Thing { static func *(lhs: Float, rhs: Self) -> Self } 不能在方法类型中使用,但class ThingBox<T: Thing>: Thing { var thing: T required init(thing: T) { self.thing = thing } static func *(lhs: Float, rhs: Self) -> Self { return Self(thing: lhs * rhs.thing) } } 是可子类化的事实意味着使用Self是不合适的。

如果不强迫它成为ThingBox,是否无法编写此类?

1 个答案:

答案 0 :(得分:2)

您的*实施有一些微妙的问题。这是你的意思:

static func *(lhs: Float, rhs: ThingBox<T>) -> Self {
    return self.init(thing: lhs * rhs.thing)
}

首先,您不能将Self用作参数类型。你必须明确。 Self表示“实际类型”,如果您可以将其用于子类,则会违反LSP。例如,假设我有类型AnimalDog(具有明显的关系)。说我写了这个函数:

class Animal {
    func f(_ a: Self) { ... }
}

具有Animal.fAnimal占用的含义,但Dog.f只会Dog,但会占用Cat }。所以你会期望以下是真实的:

dog.f(otherDog) // this works
dog.f(cat) // this fails

但这违反了替代规则。如果我写这个怎么办:

let animal: Animal = Dog()
animal.f(cat)

这应该是合法的,因为Animal.f可以接受任何Animal,但Dog.f的实施不能带猫。类型不匹配。繁荣。所以这不合法。 (对于返回类型,此限制不存在。我会将其作为练习留给读者。尝试创建一个类似上面的示例,以便返回Self。)

第二个错误只是语法错误。它不是Self(),而是self.init()。在静态方法中,self是动态类型(这是您想要的),并且Swift要求您在使用此方式时显式调用init。这只是语法,而不是像其他类似的深层类型问题。

Swift无法继承您所谈论的内容。如果你想重载,那很好,但你必须明确表示类型:

class OtherBox: ThingBox<Int> {
    static func *(lhs: Float, rhs: OtherBox) -> Self {
        return self.init(thing: lhs * rhs.thing)
    }
}

这完全符合您的要求,但必须添加到每个孩子身上;它不会自动与协方差继承。斯威夫特没有强大的协方差系统来表达它。

也就是说,当你开始以这种方式混合泛型,协议和子类时,你会遇到许多很多奇怪的角落情况,这都是由于数学原因和当前的Swift限制。您应该仔细询问您的实际代码是否需要这么多参数化。我遇到这些问题的大多数情况都是过度设计的“万一我们需要它”,只是简化你的类型并使具体内容成为解决你想要编写的实际程序所需的一切。并不是说构建基于高级类型的非常通用的算法并不好,但Swift现在不是那种语言(可能永远不会;添加这些功能会有很多成本)。 / p>