簡體   English   中英

如何在Swift中將[Int8]轉換為[UInt8]

[英]How to cast [Int8] to [UInt8] in Swift

我有一個只包含字符的緩沖區

let buffer: [Int8] = ....

然后我需要將它傳遞給一個以[UInt8]為參數的函數process

func process(buffer: [UInt8]) {
    // some code
}

將[Int8]緩沖區傳遞給[Int8]的最佳方法是什么? 我知道下面的代碼可以工作,但在這種情況下,緩沖區只包含一堆字符,並且不必使用map等函數。

process(buffer.map{ x in UInt8(x) }) // OK
process([UInt8](buffer)) // error
process(buffer as! [UInt8]) // error

我正在使用Xcode7 b3 Swift2。

IMO,這樣做的最好方法是在整個應用程序中堅持使用相同的基本類型,以避免完全需要進行強制轉換/強制。 也就是說,要么在任何地方使用Int8 ,要么使用UInt8 ,但不能同時使用兩者。

如果你別無選擇,例如你使用兩個你無法控制的獨立框架,其中一個使用Int8而另一個使用UInt8 ,那么你應該使用map如果你真的想使用Swift。 后兩行來自你的例子( process([UInt8](buffer))process(buffer as! [UInt8]) )看起來更像C方法的問題,就是我們不在乎這個區域在內存中是一個有關整數的數組,我們現在將它看作是無符號的。 這基本上把整個Swift的強類型概念拋到了窗口。

我可能嘗試做的是使用延遲序列。 例如,檢查是否可以通過以下方式提供process()方法:

let convertedBuffer = lazy(buffer).map() {
    UInt8($0)
}

process(convertedBuffer)

這至少可以節省額外的內存開銷(否則你必須保留2個數組),並且可能會節省一些性能(由於懶惰)。

我大致同意你應該堅持使用map的其他答案,但是,如果你的數組非常龐大,並且創建一個完整的第二個緩沖區只是為了轉換為相同的位模式真的很痛苦,你可以這樣做:

// first, change your process logic to be generic on any kind of container
func process<C: CollectionType where C.Generator.Element == UInt8>(chars: C) {
    // just to prove it's working...
    print(String(chars.map { UnicodeScalar($0) }))
}

// sample input
let a: [Int8] = [104, 101, 108, 108, 111]  // ascii "Hello"

// access the underlying raw buffer as a pointer
a.withUnsafeBufferPointer { buf -> Void in
    process(
        UnsafeBufferPointer(
            // cast the underlying pointer to the type you want
            start: UnsafePointer(buf.baseAddress), 
            count: buf.count))
}
// this prints [h, e, l, l, o]

注意withUnsafeBufferPointer意味着它所說的。 這是不安全的,如果你弄錯了你可以破壞記憶(尤其要小心計數)。 它基於您的外部知識工作,例如,如果任何整數是負數,那么您的代碼不會介意它們成為損壞的無符號整數。 你可能知道,但是Swift類型的系統不能,所以它不會允許它而不訴諸不安全的類型。

也就是說,上述代碼是正確的並且在規則范圍內, 如果您需要性能優勢,這些技術是合理的。 除非你處理大量的數據或編寫一個你稱之為無數次的庫,否則你幾乎肯定不會。

值得注意的是,在某些情況下,數組實際上並未由連續緩沖區支持(例如,如果它是從NSArray .withUnsafeBufferPointer ),在這種情況下,調用.withUnsafeBufferPointer將首先將所有元素復制到一個連續的數組中。 此外,Swift數組是可擴展的,因此底層元素的副本通常隨着數組的增長而發生。 如果性能是絕對關鍵的,你可以考慮使用分配自己的記憶UnsafeMutablePointer ,並用它使用固定大小的風格UnsafeBufferPointer

對於一個幽默但絕對不在你不應該實際使用的規則示例中,這也將起作用:

process(unsafeBitCast(a, [UInt8].self))

值得注意的是,這些解決方案與a.map { UInt8($0) }因為如果你傳遞一個負整數,后者將在運行時陷阱。 如果有可能,您可能需要先過濾它們。

你不能在Swift中轉換數組。 看起來像你可以,但真正發生的是你逐一投射所有元素。 因此,只有在可以強制轉換元素時, 才能對數組使用強制轉換表示法。

好吧,你不能在Swift中的數值類型之間強制轉換。 你必須強迫,這是一個完全不同的東西 - 也就是說,你必須根據原始對象創建一個不同數字類型的新對象。 使用期望UInt8的Int8的唯一方法是強制它: UInt8(x)

因此,對於整個Int8 數組一個 Int8的情況是正確的。 你不能從一個Int8數組轉換為一個UInt8數組,而不是你可以構建其中一個 結束UInt8數組的唯一方法是強制所有元素。 這正是你的map調用所做的。 這是做到這一點的方法; 說這是“不必要的”是沒有意義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM