swift - 如何将通用类型 SignedNumeric 转换为 Float?
问题描述
我正在创建一些实用程序类存储数值(Int、Float、Double 等......)。它也有最小值和最大值。
我需要将值转换为百分比。
所以我在操场上写了如下课程:
import UIKit
class Series<T: SignedNumeric> {
let minValue: T
let maxValue: T
var datas: [T] = []
let range: T
init(minValue: T, maxValue: T) {
self.minValue = minValue
self.maxValue = maxValue
self.range = (maxValue - minValue)
self.datas = []
}
func percent(value: T) -> Float {
let v: Float = value as! Float
let m: Float = minValue as! Float
let r: Float = range as! Float
return (v - m) / r
}
}
let s = Series<Int>(minValue: -100, maxValue: 100)
s.datas = [20, 0, 40, -100, 100]
Float(s.datas[0] - s.minValue) / Float(s.range)
Float(s.datas[1] - s.minValue) / Float(s.range)
Float(s.datas[2] - s.minValue) / Float(s.range)
Float(s.datas[3] - s.minValue) / Float(s.range)
Float(s.datas[4] - s.minValue) / Float(s.range)
s.percent(value: s.datas[0]) // ERROR !!!
当调用 s.percent(value: s.datas[0]) 时,它崩溃了。
如何编写 percent() 函数?
解决方案
并非每个SignedNumeric
都可以转换为Float
. 回想一下,要成为SignedNumeric
,您需要能够:
- 消极和积极
- 倍增
- 被加减
- 有一个幅度是
Comparable
和Numeric
- 可以从整数转换
最后 4 个需求都继承自Numeric
. 我们可以轻松地构建自己的类型来完成所有这些事情。这是一个人为的例子:
struct MyNumber: SignedNumeric, Comparable {
private var secret: [String]
private var isNegative: Bool
private var number: Int { secret.count }
static func *= (lhs: inout MyNumber, rhs: MyNumber) {
lhs = lhs * rhs
}
static func * (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
MyNumber(secret: Array(repeating: "", count: lhs.number * rhs.number), isNegative: lhs.isNegative != rhs.isNegative)
}
init(integerLiteral value: Int) {
let int = value
isNegative = int < 0
secret = Array(repeating: "", count: abs(int))
}
static func < (lhs: MyNumber, rhs: MyNumber) -> Bool {
lhs.number < rhs.number
}
init?<T>(exactly source: T) where T : BinaryInteger {
guard let int = Int(exactly: source) else {
return nil
}
self.init(integerLiteral: int)
}
var magnitude: MyNumber {
MyNumber(secret: secret, isNegative: false)
}
static func - (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
if lhs < rhs {
return -(rhs - lhs)
} else {
return MyNumber(secret: Array(repeating: "", count: lhs.number - rhs.number))
}
}
prefix static func - (operand: MyNumber) -> MyNumber {
MyNumber(secret: operand.secret, isNegative: !operand.isNegative)
}
mutating func negate() {
isNegative.toggle()
}
init(secret: [String], isNegative: Bool = false) {
self.secret = secret
self.isNegative = isNegative
}
typealias Magnitude = MyNumber
static func + (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
MyNumber(secret: lhs.secret + rhs.secret)
}
typealias IntegerLiteralType = Int
}
<insert whoever is doing the conversion here>到底怎么会知道,要转换MyNumber
为Float
,它必须这样做Float(aMyNumber.secret.count)
!?更不用说secret
是私人的了。
另一方面,Float.init
确实知道如何将BinaryFloatingPoint
s 和BinaryInteger
s 转换为Float
,因为这些协议定义了必要的属性,以便Float.init
可以理解它们的表示方式。例如,BinaryInteger
s 由 s 表示words
,它是 s 的一个RandomAccessCollection
,UInt
由 s 索引Int
。
我建议您只将该percent
方法添加到Series
它真正有意义的类型中:
extension Series where T : BinaryInteger {
func percent(value: T) -> Float {
let v: Float = Float(value)
let m: Float = Float(minValue)
let r: Float = Float(range)
return (v - m) / r
}
}
IMO,这对任何人都有意义T : FloatingPoint
,而不仅仅是T : BinaryFloatingPoint
:
extension Series where T : FloatingPoint {
func percent(value: T) -> T {
let v = value
let m = minValue
let r = range
return (v - m) / r
}
}
由于FloatingPoint
也支持除法,因此您无需转换为Float
!
推荐阅读
- python - 如何在另一个文件中的文件中搜索字符串
- sql - 检查表中的所有行是否在几列中具有某些值
- javascript - 如何在 NodeJS 的 LEFT JOIN 上将 SQL 查询的结果放入自己的对象中?
- powershell - 如何在 Server 2016 上使用 Powershell 远程重启服务
- c# - 如何在VS2019中为C#设置环境变量
- javascript - 使用 Array.map() 渲染动态数组,但仅适用于选定的值
- c++ - 有没有办法为类中的所有成员可选地使用`std::optional`
- google-chrome - 下载铬失败
- discord.js - 我无法将已在语音通道中的用户移动到另一个语音通道
- ios - LazyVGrid 中的 NavigationLink 循环返回所有条目,SwiftUI