简体   繁体   English

Swift 3:如何检查通用数组的类型

[英]Swift 3: How to check the type of a generic array

I declare a generic array 我声明一个通用数组

  fileprivate var array: [T?]

I have a method average(), which will calculate average if 'T' is Int or Float; 我有一个方法average(),如果'T'是Int或Float,它将计算平均值; otherwise returns 0 否则返回0

  public   func average() -> Float {
    var mean = 0
    if T is Int or Float {
     for   index in (0..<array.count-1){
         mean = mean+array[index]
        }
        mean = mean/array.count
     }
     return mean;
  }

Question: How will I check if array is holding Int/Float ( if T is Int or Float , in above code) 问题:如何检查数组是否持有Int / Float( 如果上面的代码中T为Int或Float则为

This is a tool for protocols. 这是用于协议的工具。 The useful protocols for your problem are FloatingPoint to handle floating point types (like Float ) and Integer to handle signed integer types (like Int ). 对于您的问题有用的协议是FloatingPoint处理浮点类型(如Float )和Integer处理有符号整数类型(如Int )。 These have slightly different implementations, so it's best to write each one separately. 它们的实现略有不同,因此最好分别编写每个。 Doing this will ensure that this method is only available for appropriate types of T (rather than all possible types, and just returning 0 in those cases). 这样做将确保此方法仅适用于适当的T类型(而不是所有可能的类型,在这些情况下仅返回0)。

extension MyStruct where T: FloatingPoint {
    func average() -> T {
        let sum = array.flatMap{$0}.reduce(0, +)
        let count = T(array.count)
        return sum.divided(by: count)
    }
}

extension MyStruct where T: Integer {
    func average() -> Float {
        let sum = array.flatMap{$0}.reduce(0, +)
        let count = array.count
        return Float(sum.toIntMax()) / Float(count.toIntMax())
    }
}

EDIT: Following up a bit more on Caleb's comments below, you may be tempted to think it's ok to just convert integers into floats to generate their average. 编辑:下面对Caleb的评论进行了更多介绍,您可能会认为将整数转换为浮点数以生成平均值是可以的。 But this is not safe in general without careful consideration of your ranges. 但是,如果不仔细考虑范围,通常这是不安全的。 For example, consider the average of [Int.min, Int.max] . 例如,考虑[Int.min, Int.max]的平均值。 That's [-9223372036854775808, 9223372036854775807] . 那是[-9223372036854775808, 9223372036854775807] The average of that should be -0.5, and that's what's returned by my example above. 平均值应为-0.5,这就是我上面的示例所返回的结果。 However, if you convert everything to floats in order to sum it, you'll get 0, because Float cannot express Int.max precisely. 但是,如果将所有内容都转换为浮点数以求和,则会得到0,因为Float无法精确表示Int.max I've seen this bite people in live code when they do not remember that for very large floats, x == x+1 . 我见过有人在实时代码中咬人,当他们不记得很大的浮点数时, x == x+1

Float(Int.max) == Float(Int.max - 1) // true

You will need to iterate over your array and use "if let" to unwrap the type of the values in the array. 您将需要遍历数组,并使用“ if let”解开数组中值的类型。 If they are ints handle them one way, if they are floats handle them another way. 如果它们是整数,则以一种方式处理它们;如果它们是浮点数,则以另一种方式处理它们。

//while iterating through your array check your elements to see if they are floats or ints. //在遍历数组时,请检查您的元素以查看它们是浮点数还是整数。

if let stringArray = T as? Int {
    // obj is a string array. Do something with stringArray
}
else {
    // obj is not a string array
}

You can use the type method introduced in Swift 3 in the following way: 您可以通过以下方式使用Swift 3中引入的type方法:

let type = type(of: array)
print("type: \(type)") // if T is String, you will see Array<Optional<String>> here

Here's a high level description: 这是一个高级描述:

... inside a loop which allows indexing
if let ex = array[index] as? Int {
    your code
    continue // go around the loop again, you're all done here
}
if let ex = array[index] as? Float {
    // other code
    continue  // go around the loop again, you're all done here
}
// if you got here it isn't either of them
// code to handle that
... end of inside the loop

I can explain further if that isn't clear enough. 如果还不够清楚,我可以进一步解释。

This is probably the simplest way to do it: 这可能是最简单的方法:

var average: Float {
    let total = array.reduce(0.0) { (runningTotal, item) -> Float in

        if let itemAsFloat = item as? Float {
            return runningTotal + itemAsFloat
        }
        else if let itemAsInt = item as? Int {
            return runningTotal + Float(itemAsInt)
        }
        else {
            return runningTotal
        }
    }
    return total / Float(array.count)
}

Obviously if you want it can be a function and depending on how you're wanting to use it you may need to tweak it. 显然,如果您希望它可以是一个函数,则可能需要对其进行调整,具体取决于您希望使用它的方式。

*Note that it's possible to have both Int and Float in an array of T . *请注意,有可能在T数组中同时包含IntFloat eg if T is Any . 例如,如果TAny

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM