2016-06-27 19 views
2

我真的很困難,someData[start...stop]返回MutableRandomAccessSlice。我的someData是一個let開始,所以爲什麼我想要一個可變的東西?爲什麼我不能得到RandomAccessSlice。然而,真正令人沮喪的是,它返回的API與原始源不兼容。有了Data,我可以使用.withUnsafeBytes,但對於這個後代並不是這樣。而且如何將切片變回數據也不清楚。沒有初始化需要其中的一個。數據<-> MutableRandomAccessSlice

我可以使用subdata(in:)方法而不是下標,但是,如果我只想要一個子集合表示的行爲與原始集合相似,那麼下標的意義何在。此外,subdata方法只能做打開的子範圍,爲什麼下標可以關閉和打開。這僅僅是他們還沒有完成Swift3最終的決定嗎?

回答

4

請記住,您收到的MutableRandomAccessSlice類型,而不是引用類型。它只是意味着,如果你喜歡,你可以修改它,但它沒有任何關係的事情,你切出來的:

let x = Data(bytes: [1,2,3]) // <010203> 
var y = x[0...1] 
y[0] = 2 
x // <010203> 

如果您在code看,你會注意到,目的是用來返一個自定義切片類型:

public subscript(bounds: Range<Index>) -> MutableRandomAccessSlice<Data> { 
    get { 
     return MutableRandomAccessSlice(base: self, bounds: bounds) 
    } 
    set { 
     // Ideally this would be: 
     // replaceBytes(in: bounds, with: newValue._base) 
     // but we do not have access to _base due to 'internal' protection 
     // TODO: Use a custom Slice type so we have access to the underlying data 
     let arrayOfBytes = newValue.map { $0 } 
     arrayOfBytes.withUnsafeBufferPointer { 
      let otherData = Data(buffer: $0) 
      replaceBytes(in: bounds, with: otherData) 
     } 
    } 
} 

也就是說,自定義切片對於接受數據的函數仍然是不可接受的。但是,這與其他類型一致,如Array,它切片到ArraySlice,而ArraySlice不能在需要Array的地方傳遞。這是設計的(對於Data也可能出於同樣的原因)。關注的是,一個切片「釘住」所有支持它的內存。所以如果你從兆字節的數據中取出一個3字節的片並將它存儲在一個ivar中,那麼整個兆字節就不得不四處閒逛。理論(根據Swift開發者的說法)是數組可能很大,所以你需要小心切分它們,而字符串通常要小得多,所以String可以切成一個String。

以我迄今爲止的經驗,你一般都想要subdata(in:)。我對它的實驗是它在速度上與切片非常相似,所以我相信它仍然是在寫入時拷貝的(但它似乎並沒有在我的初始測試中固定內存)。儘管如此,我只在Mac上測試過。 iOS設備上可能存在更顯着的性能差異。

+0

這是非常明確和簡潔的答案! –

0

基於羅布的意見,我只是說了以下pythonesque標延伸:

extension Data { 
    subscript(start:Int?, stop:Int?) -> Data { 
     var front = 0 
     if let start = start { 
      front = start < 0 ? Swift.max(self.count + start, 0) : Swift.min(start, self.count) 
     } 
     var back = self.count 
     if let stop = stop { 
      back = stop < 0 ? Swift.max(self.count + stop, 0) : Swift.min(stop, self.count) 
     } 
     if front >= back { 
      return Data() 
     } 
     let range = Range(front..<back) 
     return self.subdata(in: range) 
    } 
} 

這樣,我可以做

let input = Data(bytes: [0x60, 0x0D, 0xF0, 0x0D]) 
input[nil, nil] // <600df00d> 
input[1, 3]  // <0df0> 
input[-2, nil] // <f00d> 
input[nil, -2] // <600d> 
相關問題