一个轻量级协议,用于描述可以提供自身样本的类型。
请注意,此协议的意图不是规定样本是常量还是随机的;它们可以是常量也可以是随机的,具体取决于用例。 将此协议的使用与诸如 SwiftCheck
的 Arbitrary
之类的东西结合使用非常容易,可以传递任意值作为样本,或者维护一小组常量样本,并访问任意随机生成的值。
Sampleable
要求其遵循者提供一个静态方法。
static var sample: Self { get }
此方法仅返回遵循类型的样本值。
一个 Sampleable
类型随后可以继续提供任何可选方法,这些方法否则具有合理的默认实现。
static var successSample: Self? { get }
static var failureSample: Self? { get }
static var samples: [Self] { get }
前两个默认为 nil
,第三个默认为仅包含 Self.sample
返回值的数组。
除了提供一种提供样本的标准方法之外,Sampleable
协议还提供了一系列静态函数,这些函数可以通过扩展来组合来自其他 Sampleable
类型的样本。 这些函数真正的美妙之处在于,它们采用一个闭包,该闭包使用多个其他类型的样本构造 Self
,并且它会传递每个输入类型的一个样本,直到输入类型的样本用完为止。 反过来,它们会生成一个 Self
的数组。 这很难解释,但希望以下示例能阐明其操作。 如果可以这样理解,那么执行的操作本质上是 zipWith
,其中每个输入类型的样本都与 Self
的构造函数压缩在一起。
考虑以下三个 Sampleable
遵循者。
extension Int: Sampleable {
public static var sample: Int { return samples[0] }
public static var samples: [Int] {
return [1, 2, 3, 4]
}
}
extension String: Sampleable {
public static var sample: String { return samples[0] }
public static var samples: [String] {
return ["A", "B"]
}
}
请注意,String
提供了两个样本,而 Int
提供了四个样本。 这很重要,因为以下操作(很像 zipWith
)将在到达最短的样本数组的末尾时停止。
let composedSamples = String.samples(using: String.self, Int.self) { string, int in
return "\(string)\(int)"
}
这将生成 Strings
数组 ["A1", "B2"]
。 请注意,它从每个输入类型中获取了第一个样本并将其传递给闭包,然后对每个输入类型的第二个样本执行了相同的操作,然后它耗尽了第一个输入类型的样本,因此完成了。
这种类型的组合可以开箱即用地与最多 8 种输入类型完成(当然,您可以自己添加更多),并且示例中第一个输入类型与结果类型匹配没有任何特殊之处,这完全是偶然的。