Swift 4-尝试使用泛型来减少公式化代码的挑战 [英] Swift 4 -- Challenge trying to use Generics to reduce formulaic code

查看:82
本文介绍了Swift 4-尝试使用泛型来减少公式化代码的挑战的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从今天早上开始的简单任务开始,即在SCNVector3上测试一些数学函数,最后陷入协议和泛型杂草的泥潭.我一直在尝试实现一个概念上简单的扩展,该扩展允许生成随机的SCNVector3,这对于生成测试特别有用.

I started this morning with the simple task of testing some math functions on SCNVector3s and ended up bogged down in the weeds of protocols and generics. I have been trying to implement a conceptually simple extension that allows for the production of random SCNVector3s which is especially useful for generative testing.

以下swift脚本确实确实允许人们轻松生成随机向量.面临的挑战是减少实现三个维度(8个功能)的打开和关闭范围的各种组合所固有的代码复制.尽我所能,我无法弄清楚如何使用泛型函数和/或协议将这种功能折叠为一个单一方法,在我的C ++看来,这似乎是一件微不足道的任务. las,我了解到,不能简单地将泛型和协议视为等同于模板.

The following swift script does indeed allow one to easily generate random vectors. The challenge is to reduce the code replication inherent in implementing the various combinations of open and closed ranges for three dimensions (8 functions). Try as I might, I cannot figure out how to use a generic functions and/or protocols to collapse this functionality into a single method which to my C++ mind seems like a trivial task. Alas, I have learned that one can not simply think of generics and protocols as equivalent to templates.

除参数类型外,所有函数的文本都是完全等效的-这使我难以复制代码.即使那会在几个小时前结束我的悲剧传奇,我也无法自拔.

The text of all the functions is exactly equivalent save for the argument type -- which makes it too painful for me to replicate the code. I just can't bring myself to do it even though that would have ended my tragic saga hours ago.

在解决方案方面的任何帮助将不胜感激.

Any help on a solution would be greatly appreciated.

#!/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)

推荐答案

您可以添加一个协议,我们称其为Randomizable,该协议在同一保护伞下将RangeClosedRange连接在一起,这将消除重复(耶:))

You could add a protocol, let's call it Randomizable, that joins Range and ClosedRange under the same umbrella, this will eliminate the duplication (yay :) )

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())
    }
}

请注意,由于Randomizable具有关联类型,因此可以使用该协议的域受到限制,您可以通过删除Value关联类型并将其硬编码为CGFloat来规避该问题.虽然这样会使协议的灵活性降低.

As a note, because Randomizable has associated types, the domain where that protocol can be used is limited, you can circumvent that by removing the Value associated type and hardcoding it to CGFloat. Though that would make the protocol less flexible.

这篇关于Swift 4-尝试使用泛型来减少公式化代码的挑战的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆