在Swift中,协议可以在定义中声明init()
方法。然而,我无法想到除了强制符合类定义init()
之外,这解决了任何问题的用例。我们可以在协议类型上调用声明的方法,但是协议上的init不能用于实例化其对象,这是其唯一的目的。
声明协议中的init()
方法解决了什么问题?
在Swift中,协议可以在定义中声明init()
方法。然而,我无法想到除了强制符合类定义init()
之外,这解决了任何问题的用例。我们可以在协议类型上调用声明的方法,但是协议上的init不能用于实例化其对象,这是其唯一的目的。
声明协议中的init()
方法解决了什么问题?
init
的协议:protocol JSONCreatable {
init(fromJson json: JSON)
}
然后,在一个通用函数中,我返回符合该协议的类:
import SwiftyJSON
extension JSON {
func asObject<T>() -> T? where T: JSONCreatable {
if isEmpty {
return nil
}
return T(fromJson: self)
}
func asArray<T>() -> [T] where T: JSONCreatable {
return array?.map{ json in T(fromJson: json) } ?? []
}
}
let user: User = json["user"].asObject()
let results: [Element] = json["elements"].asArray()
<T:SomeProtocol>() - > T
的通用函数更好地编写为SomeProtocol
扩展中的初始化程序。在[T]
的情况下,我还会考虑在受限制的Array
扩展中编写一个init
。不过这可能只是个人偏好。我认为let array = [SomeJSONCreatable](json:someJSON)
比let array:[SomeJSONCreatable] = someJSON.asArray()
更自然。 - Hamish它强制类从某些数据中具有init(data: data)
方法,例如:
protocol JSONable {
init(data: JSON)
}
强制所有实现了JSONable
接口的类都要有一个从JSON
初始化的方法,这样你就可以确保始终能够从JSON
创建一个实例。
JSONable(data: <*someJson*>)
的东西。 - Sumeetfunc f<T: JSONable>(jsonString: String) -> T { return T(data: parseJSON(jsonString)) }
。 - user28434'mstep这通常用于允许协议扩展和泛型占位符约束协议,以调用符合该协议的具体类型上的初始化程序。例如,考虑 RangeReplaceableCollection
的默认实现 init<S : Sequence>(_ elements: S)
:
extension RangeReplaceableCollection {
// ...
/// Creates a new instance of a collection containing the elements of a
/// sequence.
///
/// - Parameter elements: The sequence of elements for the new collection.
public init<S : Sequence>(_ elements: S) where S.Iterator.Element == Iterator.Element {
self.init()
append(contentsOf: elements)
}
// ...
}
如果在 RangeReplaceableCollection
协议中没有定义 init()
为必需项,扩展就无法知道我们可以调用 init()
来创建符合类型的新实例。
但是它也可以直接在泛型和扩展之外使用 - 例如,它可以用于构建一个由给定存在类型的元类型(表示“一些遵循协议的具体类型”的元类型)所表示的新实例:
protocol P {
init()
}
struct S : P {
init() {}
}
let s: P = S()
let s1 = type(of: s).init() // creates a new instance of S, statically typed as P.
type(of: s)
返回 s
的动态类型为 P.Type
(一种存在类型元类型),因为 s
静态类型为 P
。请记住,type(of:)
是一个 (T) -> T.Type
操作。
init()
构造了一个新的实例,其底层具体类型为 S
。
新实例的静态类型为 P
(即封装在存在容器中)。
type(of: s)
在这里会返回 S.Type
。此外,我们不能在 P.Type
上调用初始化程序。 - Shubhams
的类型是 P
。而你可以在 P.Type
上调用初始化器 - 请随意尝试 :) 只有 P.Protocol
(协议本身的类型)不能调用初始化器,因为它不代表具体的类型。 - Hamishtype(of: s)
返回 S.Type
,而 P.Type.init()
则失败并提示 "P.Type没有名为 init 的成员"。 - Shubhams
打成了大写的S
- P.Type.init()
是不合法的。你需要在元类型值上调用init()
,并将其类型定义为P.Type
(例如,当应用于某些P
表达式时,type(of:)
的结果)。 - HamishS
的对象之后,s
的动态类型会更改为 S.type
。 - ShubhamS
,所以不需要处理存在类型 :) (但在 S.Type
上调用 init
与在 P.Type
上调用它一样有效)。 - Hamish