为什么在通用Array where子句中必需关键字init是必需的?

时间:2018-11-12 13:47:30

标签: arrays swift generics extension-methods

在此下标代码中:

{
     "_id" : ObjectId("5be7fc909625592852d422b4"),
     "time" : ISODate("2018-11-11T09:55:28.704Z"),
    "receiver" : ObjectId("5be5d727d3f24e06b144e229"),
    "createdAt" : ISODate("2018-11-11T09:55:28.718Z"),
    "updatedAt" : ISODate("2018-11-11T09:55:28.718Z"),
}
{
    "_id" : ObjectId("5be807902b789e5c3c05dc5e"),
    "time" : ISODate("2018-11-11T10:42:24.410Z"),
    "receiver" : ObjectId("5be5d727d3f24e06b144e229"),
    "createdAt" : ISODate("2018-10-09T18:30:00Z"),
    "updatedAt" : ISODate("2018-10-09T18:30:00Z"),
}

为什么extension Array where Element: Foo { subscript(key: String) -> Any? { get { return self.first(where: { $0.key == key }) } set { self.append(Element(key: key, value: newValue)) } } } class Foo { var key: String var value: Any? // Why "required"? required init(key: String, value: Any?) { self.key = key self.value = value } } 必须位于Foo.init前面?

如果删除它,则会出现此错误:

required

2 个答案:

答案 0 :(得分:3)

您需要标记初始化器required,因为您是从通用扩展名中使用它的,该扩展名适用于从Foo继承的所有类型(包括Foo本身)。但是,如果未将初始化程序标记为required,则Foo子类可能无法继承该初始化程序,以防它们定义了至少一个指定的初始化程序,如Automatic Initializer Inheritance中所述。

因此,除非您标记了init(key: String, value: Any?) Foo的{​​{1}}初始化程序,否则您的通用Array扩展程序无法保证扩展程序适用的所有类型都存在该扩展程序中调用的初始化程序方法

如果您只想将扩展名应用于required类,而又不想将其应用于子类,则可以使用Foo,在这种情况下,您无需标记初始化程序是必需的,因为保证extension Array where Element == Foo {...类型具有该初始化程序。

答案 1 :(得分:3)

  

required关键字意味着继承的类必须提供该方法的实现。

extension Array where Element: Foo意味着扩展应该适用于所有继承自Foo的类,因此所有required都可以实现init(key: String, value: Any?)

因此,必须添加required关键字以确保这一点。

如果它是extension Array where Element == Foo,则不需要required,因为对于类型Foo,定义了init并带有适当的签名,并且不需要任何签名检查。

进行Foo的决赛(final class Foo {})也将消除required中的需求。