Type 应该采用啥协议来让泛型函数将任何数字类型作为 Swift 中的参数?

Posted

技术标签:

【中文标题】Type 应该采用啥协议来让泛型函数将任何数字类型作为 Swift 中的参数?【英文标题】:What protocol should be adopted by a Type for a generic function to take any number type as an argument in Swift?Type 应该采用什么协议来让泛型函数将任何数字类型作为 Swift 中的参数? 【发布时间】:2014-10-23 21:25:24 【问题描述】:

我想让一个函数在 Swift 中接受任何数字(Int、Float、Double、...)

func myFunction <T : "What to put here"> (number : T) ->  
    //...

不使用 NSNumber

【问题讨论】:

【参考方案1】:

更新: 下面的答案原则上仍然适用,但 Swift 4 完成了对数字协议的重新设计,因此通常不需要添加您自己的协议。在构建自己的系统之前,请查看standard library's numeric protocols。


这实际上在 Swift 中是不可能开箱即用的。为此,您需要创建一个新协议,使用您将在泛型函数中使用的任何方法和运算符进行声明。此过程对您有用,但具体细节将在一定程度上取决于您的通用函数的作用。这是获取数字 n 并返回 (n - 1)^2 的函数的方法。

首先,定义您的协议,使用运算符和一个接受Int 的初始化程序(这样我们就可以减去一个)。

protocol NumericType 
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
    init(_ v: Int)

所有数值类型已经实现了这些,但此时编译器并不知道它们是否符合新的NumericType 协议。你必须明确这一点——Apple 称之为“通过扩展声明采用协议”。我们将为DoubleFloat 和所有整数类型执行此操作:

extension Double : NumericType  
extension Float  : NumericType  
extension Int    : NumericType  
extension Int8   : NumericType  
extension Int16  : NumericType  
extension Int32  : NumericType  
extension Int64  : NumericType  
extension UInt   : NumericType  
extension UInt8  : NumericType  
extension UInt16 : NumericType  
extension UInt32 : NumericType  
extension UInt64 : NumericType  

现在我们可以编写我们的实际函数,使用NumericType 协议作为通用约束。

func minusOneSquared<T : NumericType> (number : T) -> T 
    let minusOne = number - T(1)
    return minusOne * minusOne


minusOneSquared(5)              // 16
minusOneSquared(2.3)            // 1.69
minusOneSquared(2 as UInt64)    // 1

【讨论】:

谢谢你,这么好的答案! 是的,这比在***.com/a/28457725/466698 中实现所有自己的运算符要好得多,为什么 Swift 本身不包含这样的协议? 一些谨慎。 NumericType,在此处实现,作为 Self 要求。因此,您将无法执行 var values = [NumericType] 之类的操作。如果你想这样做,你必须提供自己的运营商,唉。 使用这种方法有没有办法将T 转换为Int?喜欢Int(number)?或者使用其他功能,如floor(number) 在 Swift 4 中,Numeric 协议定义了除 '/' 和 '%' 之外的所有操作符。该协议由浮点和整数类型实现。【参考方案2】:

作为与评论打击相关的澄清以及对于那些不太了解 Swift 协议的人来说,这里的重点是在 Numeric Type 中声明的方法已经由已声明一致性的每个类型实现。例如,因为 Int 类型已经实现了...

func +(lhs: Self, rhs: Self) -> Self

...在 NumericType 协议中不需要进一步的实现细节。

在这种情况下,协议声明的目的不是为它的任何实现类型添加新方法,而是提供一个统一的外观,让编译器知道任何实现 NumericType 的东西都支持全套 Swift 数学运算符.因为每个添加了 NumericType 一致性的类型已经实现了 NumericType 中的所有方法,所以它们完全符合协议所需要做的就是声明它们符合...

extension Int : NumericType  

【讨论】:

以上是关于Type 应该采用啥协议来让泛型函数将任何数字类型作为 Swift 中的参数?的主要内容,如果未能解决你的问题,请参考以下文章

尝试符合可等式泛型 Set 时,类型“任何”不符合协议“等式”

无法将协议的通用关联类型的值转换为预期的参数类型

Swift:将类型从属性传递给泛型函数

通用方法,其中T是type1或type2

泛型类型限定和通配符类型限定

C# 泛型是引用类型还是值类型,是根据啥判断?