繁体   English   中英

快速将影响值转换为inout通用变量

[英]swift affect value to inout generic variable

我想用T变量简化这段代码,但无法成功编译它。 希望你能给我办法。

这是我要重写的“重复”代码:

    func getIntegerValue (listValues: [Any], numValueToRead: Int, readValue: inout Int) -> Bool {
        if numValueToRead < 0 || numValueToRead >= listValues.count {
            return false
        }
        let value = listValues [numValueToRead]
        if type (of: value) == type(of: readValue) {
            readValue = value as! Int
            return true
        } else {
            return false
        }
    }

    func getStringValue (listValues: [Any], numValueToRead: Int, readValue: inout String) -> Bool {
        if numValueToRead < 0 || numValueToRead >= listValues.count {
            return false
        }
        let value = listValues [numValueToRead]
        if type (of: value) == type(of: readValue) {
            readValue = value as! String
            return true
        } else {
            return false
        }
    }

这是我编写但未编译的代码:

func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
    if numValueToRead < 0 || numValueToRead >= listValues.count {
        return false
    }
    let value = listValues [numValueToRead]
    if type (of: value) == type(of: readValue) {
        switch value {
        case let integerValue as Int:
            readValue = integerValue
        case let stringValue as String:
            readValue = stringValue
        default:
            return false
        }
        return true
    } else {
        return false
    }
}

对于那些影响,我得到了那些编译错误:readValue = integerValue->'Int'不可转换为'T'readValue = stringValue->'String'不可转换为'T'

有没有一种方法可以使用泛型将我的两个函数与唯一的函数合成?

从理论上讲,您可以通过添加强制转换来使其编译,因为您已经知道value具有类型T

    case let integerValue as Int:
        readValue = integerValue as! T
    case let stringValue as String:
        readValue = stringValue as! T

但是更好的解决方案是使用条件转换( as? T )和条件绑定( if let ):

func getValue<T>(listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
    if numValueToRead < 0 || numValueToRead >= listValues.count {
        return false
    }
    let value = listValues[numValueToRead]
    if let tvalue = value as? T {
        readValue = tvalue
        return true
    } else {
        return false
    }
}

然后适用于任意类型,不仅限于IntString

“ swiftier”方式将返回一个可选值( nil表示“无值”)。 然后可以将代码简化为

func getValue<T>(listValues: [Any], numValueToRead: Int) -> T? {
    guard listValues.indices.contains(numValueToRead) else {
        return nil
    }
    return listValues[numValueToRead] as? T
}

这应该工作:

func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
    if numValueToRead < 0 || numValueToRead >= listValues.count {
        return false
    }

    let value = listValues [numValueToRead]
    if type (of: value) == type(of: readValue) {
        if let genericValue = value as? T {
            readValue = genericValue
            return true
        }

        return false
    } else {
        return false
    }
}

乍一看,该函数的名称错误。 当它返回布尔值时,您不能调用函数getValue ...我将其称为变换或修改或获取值以外的其他东西,因为您没有获取值。

我认为此方法更适合您的需求,而不是经过测试的方法应该可以工作。

func transformValue<T>(from listValues: [Any], numValueToRead: Int, readValue: inout T?) throws -> Bool {

    // Guard suits better this case...
    guard numValueToRead > 0 || numValueToRead < listValues.count else { return false }

    let value = listValues[numValueToRead]
    if type (of: value) == type(of: readValue) {
        guard let value =  value as? T else {
            throw NSError(
                domain: "Smth",
                code: 1,
                userInfo: ["Description": "Failed to cast to generic type T"]
            )
        }
        readValue = value as? T
        return true
    }
    return false // No need to call else...
}

说明:返回可选的泛型T更安全。 您尝试投射它,失败了,并且抛出了出错的错误消息。 在我看来,省力投掷错误是一种更安全的方法,您知道出了什么问题等等。

正如@MartinR所指出的那样,返回一个nil值而不是inout + Bool组合可以得到相同的结果,但是所用的代码更少且可读性更高。 这是Swift从Objective-C导入大多数NSError **方法时也采用的路径(即删除最后一个参数,将其作为可抛出函数导入)。

这就是说,另一种方法是在Array上添加扩展以提取值:

extension Array {
    subscript<T>(_ index: Int, as type: T.Type) -> T? {
        guard 0..<count ~= index else { return nil }
        return self[index] as? T
    }
}

let arr: [Any] = [1, "two", 3, "four"]
arr[1, as: String.self] // two
arr[2, as: String.self] // nil

暂无
暂无

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

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