考虑以下几点(从实际代码中简化):
func roundedInt<T: FloatingPoint>(_ f: T) -> Int {
return Int(f.rounded())
}这在编译过程中出现了以下错误:
不能使用“Int”类型的参数列表调用“Int”类型的初始化器,因为“Int”的重载包含这些部分匹配的参数列表:(Int64)、(Word)、(UInt8)、(Int8)、(UInt16)、(Int16)、(UInt32)、(Int32)、(UInt64)、(UInt)、(Int)、(浮点)、(双)、(Float80)、(字符串、基x: Int)、(CGFloat)、(NSNumber)
我认为这意味着FloatingPoint不能与任何Int重载相匹配。
有什么简单的方法可以让这件事成功吗?或者,Swift泛型(例如,与C++模板相比)是否有一个排除这一点的限制?
发布于 2017-04-30 12:43:03
简单的C++模板只不过是一种宏、类型少的源代码替换机制.调用代码被应用模板替换,编译器将检查生成的代码是否有意义。您是对的,roundedInt<T>无界函数在C++域应该可以很好地工作。
相反,Swift泛型是按设计设计的类型,这意味着泛型代码必须是独立的,独立于给定呼叫站点的任何细节。在您的示例中,FloatingPoint协议是引导编译的类型(而不是调用代码使用的实际T类型)。
(顺便说一下,Java/C#泛型也类似Swift风格。)
对于实际问题,只需为roundedInt函数提供两个重载:
func roundedInt(_ f: Float) -> Int { ... }
func roundedInt(_ f: Double) -> Int { ... }这应该涵盖大多数用例。当然,假设您只是在编写小助手函数.而不是完整的库/框架!
否则,尝试@Sweeper基于字符串的解决方案。但请记住,除了潜在的精度损失,他正确地指出,也有一些恶劣的性能问题潜伏在那里。
发布于 2017-12-22 20:02:19
使用BinaryFloatingPoint,正如您所期望的那样,在Int可以表示的范围内工作。
func roundedInt<T: BinaryFloatingPoint>(_ f: T) -> Int {
return Int(f.rounded())
}
let x = roundedInt(Float(42.1)) // 42发布于 2017-04-30 12:34:42
这是我能想到的最好的:
func roundedInt<T: FloatingPoint>(_ f: T) -> Int {
return Int(Float80("\(f.rounded())")!)
}基本上,这是一种“欺骗”。据我所知,标准库中符合FloatingPoint的所有类型都是Float、Double和Float80。它们的字符串表示形式是相同的。这就是为什么我将字符串表示转换为Float80的原因。然后,我将这个数字转换为一个Int。
我说这是一种欺骗,因为它实际上不适用于大量的数字。当您将很大的数字放入此函数中时,会发生致命错误。经过一些试验和错误之后,我发现在64位处理器上可以传递给这个函数的最大数字是9223372036854775295,比Int.max少512个。
此外,如果您在那里通过9223372036854775295,它将返回9223372036854770000,而不是原来的数字。这很可能是因为浮点数不准确。
https://stackoverflow.com/questions/43706023
复制相似问题