Swift 4——尝试使用泛型来减少公式化代码的挑战
今天早上,我开始做一个简单的任务,在Scnvector3上测试一些数学函数,结果陷入了协议和泛型的杂草中。我一直在尝试实现一个概念上简单的扩展,它允许生成对生成性测试特别有用的随机转换 下面的swift脚本确实允许您轻松生成随机向量。挑战在于减少在实现三维(8个功能)的开放和封闭范围的各种组合时固有的代码复制。尽管我尝试了,但我无法理解如何使用泛型函数和/或协议将此功能分解为单一方法,这对我的C++思维来说似乎是一项微不足道的任务。唉,我明白了,不能简单地将泛型和协议视为等同于模板 除了参数类型之外,所有函数的文本都完全相同——这让我很难复制代码。我就是不能让自己去做,即使那会在几个小时前结束我悲惨的故事 如果您能提供任何帮助,我们将不胜感激Swift 4——尝试使用泛型来减少公式化代码的挑战,swift,generics,swift4,Swift,Generics,Swift4,今天早上,我开始做一个简单的任务,在Scnvector3上测试一些数学函数,结果陷入了协议和泛型的杂草中。我一直在尝试实现一个概念上简单的扩展,它允许生成对生成性测试特别有用的随机转换 下面的swift脚本确实允许您轻松生成随机向量。挑战在于减少在实现三维(8个功能)的开放和封闭范围的各种组合时固有的代码复制。尽管我尝试了,但我无法理解如何使用泛型函数和/或协议将此功能分解为单一方法,这对我的C++思维来说似乎是一项微不足道的任务。唉,我明白了,不能简单地将泛型和协议视为等同于模板 除了参数类型
#!/usr/bin/env swift
import SceneKit
extension SCNVector3 {
public static func random(_ range: ClosedRange<CGFloat>) -> SCNVector3 {
return SCNVector3(CGFloat.random(in: range),
CGFloat.random(in: range),
CGFloat.random(in: range))
}
public static func random(_ range: Range<CGFloat>) -> SCNVector3 {
return SCNVector3(CGFloat.random(in: range),
CGFloat.random(in: range),
CGFloat.random(in: range))
}
public static func random(_ xrange: ClosedRange<CGFloat>,
_ yrange: ClosedRange<CGFloat>,
_ zrange: ClosedRange<CGFloat>) -> SCNVector3 {
return SCNVector3(CGFloat.random(in: xrange),
CGFloat.random(in: yrange),
CGFloat.random(in: zrange))
}
}
for _ in 0...5 {
print(SCNVector3.random(0...1))
}
for _ in 0...5 {
print(SCNVector3.random(0..<1))
}
for _ in 0...5 {
print(SCNVector3.random(0...1, 0...10, 0...100))
}
SCNVector3(x: 0.30337554055051663, y: 0.3815295391899972, z: 0.4500107875772762)
SCNVector3(x: 0.8292976915969825, y: 0.09817659394351774, z: 0.9805310965643402)
SCNVector3(x: 0.10140452934182276, y: 0.13700006723273783, z: 0.003407601812085548)
SCNVector3(x: 0.2794740490735984, y: 0.8092883659638909, z: 0.7611573009648945)
SCNVector3(x: 0.5245643085628658, y: 0.08307239252197174, z: 0.4335406226121913)
SCNVector3(x: 0.43781151814220054, y: 0.061963776367431, z: 0.18073354555266563)
SCNVector3(x: 0.10427323503781749, y: 0.8816323284041111, z: 0.7307715923086391)
SCNVector3(x: 0.36332454445518303, y: 0.7568856199566694, z: 0.43190825321532156)
SCNVector3(x: 0.8236386316508026, y: 0.8079968534291148, z: 0.3294130964530748)
SCNVector3(x: 0.038760425835524304, y: 0.8453005937068554, z: 0.11379975436886769)
SCNVector3(x: 0.9980685456027362, y: 0.6776965236898836, z: 0.6814096250296368)
SCNVector3(x: 0.01414002018834537, y: 0.1922579292321731, z: 0.5310331022793705)
SCNVector3(x: 0.6720908484435982, y: 6.815521332533848, z: 47.73040146101302)
SCNVector3(x: 0.05912412792498123, y: 7.709586490036736, z: 87.70901825047801)
SCNVector3(x: 0.9603565579370552, y: 9.627783890657632, z: 83.3390228893866)
SCNVector3(x: 0.4312469801270884, y: 1.0603895571013555, z: 73.97981933311189)
SCNVector3(x: 0.8079217337794122, y: 7.901726750285889, z: 83.322147654367)
SCNVector3(x: 0.7795445386815117, y: 6.845539611004492, z: 92.24684042413436)
#/usr/bin/env swift
导入SceneKit
扩展转换程序3{
public static func random(uu范围:ClosedRange)->SConvector3{
返回SCInvector3(CGFloat.random(在:范围内),
CGFloat.random(在:范围内),
CGFloat.random(在:范围内))
}
公共静态func random(u-range:range)->SCInvector3{
返回SCInvector3(CGFloat.random(在:范围内),
CGFloat.random(在:范围内),
CGFloat.random(在:范围内))
}
公共静态函数随机(xrange:ClosedRange,
_yrange:ClosedRange,
_zrange:ClosedRange)->SCInvector3{
返回SCInvector3(CGFloat.random(in:xrange),
CGFloat.random(单位:yrange),
CGFloat.random(in:zrange))
}
}
对于0…5中的uu{
打印(SCInvector3.random(0…1))
}
对于0…5中的uu{
打印(SCInvector3.random(0..您可以添加一个协议,我们称之为可随机化的
,它将范围
和关闭范围
连接在同一个保护伞下,这将消除重复(耶:)
公共协议可随机化{
关联类型值
func random()->值
}
扩展范围:可随机化,其中BOND==CGFloat{
公共类型别名值=CGFloat
public func random()->CGFloat{
返回CGFloat.random(in:self)
}
}
扩展ClosedRange:可随机化,其中Bound==CGFloat{
公共类型别名值=CGFloat
public func random()->CGFloat{
返回CGFloat.random(in:self)
}
}
扩展转换程序3{
公共静态func random(source:R)->SCInvector3,其中R.Value==CGFloat{
返回SCInvector3(source.random(),
source.random(),
source.random())
}
公共静态func随机(
_来源:R1,,
_资料来源:R2,
_zsource:R3)->sConvector3,其中R1.Value==CGFloat,R2.Value==CGFloat,R3.Value==CGFloat{
返回SCNVector3(xsource.random(),
ysource.random(),
zsource.random())
}
}
需要注意的是,由于Randomizable
具有关联的类型,因此该协议可以使用的域是有限的,您可以通过删除值
关联的类型并将其硬编码为CGFloat
来避免这种情况。尽管这会降低协议的灵活性。您可以添加一个协议,我们称之为Randomizable
,将范围
和关闭区域
连接在同一个保护伞下,这将消除重复(耶:)
公共协议可随机化{
关联类型值
func random()->值
}
扩展范围:可随机化,其中BOND==CGFloat{
公共类型别名值=CGFloat
public func random()->CGFloat{
返回CGFloat.random(in:self)
}
}
扩展ClosedRange:可随机化,其中Bound==CGFloat{
公共类型别名值=CGFloat
public func random()->CGFloat{
返回CGFloat.random(in:self)
}
}
扩展转换程序3{
公共静态func random(source:R)->SCInvector3,其中R.Value==CGFloat{
返回SCInvector3(source.random(),
source.random(),
source.random())
}
公共静态func随机(
_来源:R1,,
_资料来源:R2,
_zsource:R3)->sConvector3,其中R1.Value==CGFloat,R2.Value==CGFloat,R3.Value==CGFloat{
返回SCNVector3(xsource.random(),
ysource.random(),
zsource.random())
}
}
需要注意的是,由于Randomizable
具有关联的类型,因此该协议可使用的域是有限的,您可以通过删除值关联的类型并将其硬编码为CGFloat
来避免这种情况。尽管这会降低协议的灵活性。ClosedRange和Range不具有相同的点。因此在这里不能使用泛型。但是可以通过删除第二个随机函数并将第三个随机函数更改为random(xrange:ClosedRange,yrange:ClosedRange=xrange,zrange:ClosedRange=xrange,zrange:ClosedRange=xrange)来缩短代码
@Quoc Nguyen:当我尝试添加默认值时,我得到了错误:使用未解析标识符
。ClosedRange和Range没有相同的点。因此我认为您不能在这里使用泛型。但是您可以通过删除第二个随机函数并将第三个随机函数更改为随机函数来缩短代码(uxRange:ClosedRange,yrange:Clo
public protocol Randomizable {
associatedtype Value
func random() -> Value
}
extension Range: Randomizable where Bound == CGFloat {
public typealias Value = CGFloat
public func random() -> CGFloat {
return CGFloat.random(in: self)
}
}
extension ClosedRange: Randomizable where Bound == CGFloat {
public typealias Value = CGFloat
public func random() -> CGFloat {
return CGFloat.random(in: self)
}
}
extension SCNVector3 {
public static func random<R: Randomizable>(_ source: R) -> SCNVector3 where R.Value == CGFloat {
return SCNVector3(source.random(),
source.random(),
source.random())
}
public static func random<R1: Randomizable, R2: Randomizable, R3: Randomizable>(
_ xsource: R1,
_ ysource: R2,
_ zsource: R3) -> SCNVector3 where R1.Value == CGFloat, R2.Value == CGFloat, R3.Value == CGFloat {
return SCNVector3(xsource.random(),
ysource.random(),
zsource.random())
}
}