What protocol should be adopted by a Type for a ge

2019-01-03 06:47发布

I want to make a function accept any number (Int, Float, Double, ...) in Swift

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

without using NSNumber

2条回答
Animai°情兽
2楼-- · 2019-01-03 07:06

As a clarification relating to the comment blow and for those that don't know Swift protocols very well, the point here is that the methods declared in Numeric Type are already implemented by each of the types for which conformance has been declared. For example, because the type Int already implements...

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

...no further implementation details are required in the NumericType protocol.

The purpose of the protocol declaration in this case is not to add new methods to any of its implementing types, but to provide a unified facade that allows the compiler to know that anything that implements NumericType supports the full set of Swift mathematical operators. Because each of the types that have had NumericType conformance added to them already implements all of the methods in NumericType, all that is needed for them to conform fully to the protocol is to declare that they conform...

extension Int : NumericType { }
查看更多
放我归山
3楼-- · 2019-01-03 07:25

Update: The answer below still applies in principle, but Swift 4 completed a redesign of the numeric protocols, such that adding your own is often unnecessary. Take a look at the standard library's numeric protocols before you build your own system.


This actually isn't possible out of the box in Swift. To do this you'll need to create a new protocol, declared with whatever methods and operators you're going to use inside your generic function. This process will work for you, but the exact details will depend a little on what your generic function does. Here's how you'd do it for a function that gets a number n and returns (n - 1)^2.

First, define your protocol, with the operators and an initializer that takes an Int (that's so we can subtract one).

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

All of the numeric types already implement these, but at this point the compiler doesn't know that they conform to the new NumericType protocol. You have to make this explicit -- Apple calls this "declaring protocol adoption with an extension." We'll do this for Double, Float, and all the integer types:

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 { }

Now we can write our actual function, using the NumericType protocol as a generic constraint.

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
查看更多
登录 后发表回答