簡體   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