swift - 实现接受并返回 Self 的协议(protocol)静态方法(快速)

标签 swift generics swift-protocols

给定一个协议(protocol),大致如下:

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可子类化意味着使用 ThingBox<T>不合适。

是否可以在不强制它为 final 的情况下编写此类? ?

最佳答案

您的*实现存在一些微妙的问题。这是您所说的实现:

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.f 将采用 Animal,但 Dog.f 将仅采用 Dog不会。因此,您会期望以下内容为真:

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 没有强大的协方差系统来表达它。

也就是说,当您开始以这种方式混合泛型、协议(protocol)和子类化时,您将遇到许多许多奇怪的极端情况,这既是由于数学原因,也是由于当前 Swift 的限制。您应该仔细询问您的实际代码是否需要这么多参数化。我遇到的大多数此类问题都是过度设计的“以防万一我们需要它”,只需简化类型并使事情具体化就可以解决您想要编写的实际程序所需的一切。这并不是说在更高级的类型上构建令人难以置信的通用算法不好,但 Swift 并不是当今适合的语言(也可能永远不会;添加这些功能需要付出很多成本)。

关于swift - 实现接受并返回 Self 的协议(protocol)静态方法(快速),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46368841/

相关文章:

ios - 结束跟踪时 UISlider 的控制事件

c# - 使用 Linq 表达式和反射获取属性值的通用方法

generics - Rust 中的通用占位符或默认值

swift - 如何在类型化为协议(protocol)的 Swift 通用数据结构中使用弱引用?

ios - Firebase 喜欢/不喜欢系统

swift - 如何快速解压缩 .gz 文件?

swift - 如何在 ios 中将数据类型声明为时间戳 - swift

c# - 如何返回以接口(interface)为返回类型的接口(interface)的实现?

ios - 如何修复协议(protocol)只能用作通用约束,因为它具有自身或关联的类型要求错误

Swift 协议(protocol)扩展,其中 Self : Equatable doesn't work