实现采用和 returns Self(在 swift 中)的协议静态方法

Implementing protocol static method that takes and returns Self (in swift)

给定协议如下:

protocol Thing {
  static func *(lhs: Float, rhs: Self) -> Self
}

如何实现一个盒子class?

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 是 subclass 的事实意味着使用 ThingBox<T> 不是合适。

难道写成这个class不强行写成final不行吗?

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

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

首先,不能使用Self作为参数类型。你必须明确。 Self 表示 "the actual type",如果您可以将其用于子类,这将违反 LSP。例如,假设我有类型 AnimalDog(具有明显的关系)。假设我写了函数:

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

的意思是Animal.f会带Animal,但是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的实现不能带猫。类型不匹配。繁荣。所以这是不合法的。 (对于 return 类型不存在此限制。我将把它留作 reader 的练习。尝试为 returning 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)
    }
}

这正是您想要的,但必须将其添加到每个 child;它不会通过协方差自动继承。 Swift 没有强大的协方差系统来表达它。

就是说,当您开始以这种方式混合泛型、协议和子类化时,您将 运行 陷入许多奇怪的极端情况,这既是由于数学原因,也是由于当前 Swift限制。您应该仔细询问您的实际代码是否需要这么多参数化。我遇到这类问题的大多数情况是 over-designed "in case we need it" 并且只需简化您的类型并使事情具体化就是解决您要编写的实际程序所需的一切。并不是说构建基于 higher-kinded 类型的令人难以置信的通用算法不好,但 Swift 并不是今天的语言(而且可能永远不会;有很多成本添加这些功能)。