Swift3 Dataオブジェクトの簡単なBSON解析をしようとしています。私はシステムと戦っているように感じる。swift(3)データストリームの構文解析の慣用方法
いくつかの入力およびスキームで始まるのをしてみましょう:
let input = Data(bytes: [2, 0x20, 0x21, 3, 0x30, 0x31, 0x32, 1, 0x10, 4, 0x40, 0x41, 0x42, 0x43])
これは軽薄なスキームは、先頭バイトは、バイト数は次のチャンクを構成する従うかを示すということで、単純なデータストリームです。そう上記において、リーディング2の0x20は、0x21で等バイト0x30から、0x31、0x32のを含む3バイトのチャンクに続く最初のチャンクであることを示している私の最初の考えである
ストリームストリーム(er、Generator、Iterator、何でも)でそれを行う。これは、複数の質問/観察結果につながる
var iter = input.makeIterator()
func parse(_ stream:inout IndexingIterator<Data>) -> Data {
var result = Data()
if let count = stream.next() {
for _ in 0..<count {
result.append(Data(bytes:[stream.next()!]))
}
}
return result
}
parse(&iter)
parse(&iter)
parse(&iter)
parse(&iter)
:だから私のようなもので終わる
1)なぜ今まで誰let
イテレータをしませんか?このことの全体的なポイントは、コレクション上の進化する位置を追跡することです。スウィフトの作者がイテレータを「すべての恩恵セマンティクス」のもとに送ることを選んだのは本当に苦労しています。つまり、すべての解析関数にinout
を入れなければならないということです。
2)IndexingIteratorで引数の型を指定しすぎているような気がします。たぶん、冗長なジェネリックに慣れる必要があるのでしょうか?そのアプローチに不満のPython Struct'esque
は、私がニシキヘビstruct.unpack()タプルが解析されたデータで返されるスタイル、ならびに未消費データをエミュレートするかもしれないと思いました。おそらく私がそれらを突然変異させない限り、データは魔法で効率的です。それは次のようになりました:
func parse2(_ data:Data) -> (Data, Data) {
let count = Int(data[0])
return (data.subdata(in: 1..<count+1), data.subdata(in: count+1..<data.count))
}
var remaining = input
var chunk = Data()
(chunk, rest) = parse2(remaining)
chunk
(chunk, rest) = parse2(remaining)
chunk
(chunk, rest) = parse2(remaining)
chunk
(chunk, rest) = parse2(remaining)
chunk
私はこれに2つの問題がありました。
1)本当に返信したいのは、data[1..count], data.subdata(in: count+1..<data.count)
です。しかし、これはMutableRandomAccessSliceを返します。どちらが全く違う種類のようですか?だから私はより多くの関与を使用して終了subdata
。
2)1つは閉じた範囲のデータを添字にすることができますが、subdata
のメソッドはオープン範囲のみをとります。それは何ですか?
でキック
、私はちょうど自分自身をロール:
class DataStream {
let data:Data
var index = 0
var atEnd:Bool {
return index >= self.data.count
}
init(data:Data) {
self.data = data
}
func next() -> UInt8 {
let byte = self.data[self.index]
self.index += 1
return byte
}
func next(_ count:Int) -> Data {
let subdata = self.data.subdata(in: self.index..<self.index + count)
self.index += count
return subdata
}
}
func parse3(_ stream:DataStream) -> Data {
let count = Int(stream.next())
return stream.next(count)
}
let stream = DataStream(data: input)
parse3(stream)
parse3(stream)
parse3(stream)
parse3(stream)
私はこのソリューション最終使用POVから幸せ。私はすべての種類のものを行うためにDataStreamを肉体化することができます。しかし、...私は今、暴かれた道を離れて、私が "それを得る"(敏速な電球)ではないように感じています。
TL; DRバージョン
これは遊んでた後、私は彼らに遭遇されたものに基づいて、それらからデータを抽出、自分は好奇心どのようなデータ構造体を通じてストリーミングするための最も慣用的な方法を見つけます。
#2のためにあなたは私があなたの欲求不満を見ることができるタイプの別名 – Alexander
を使用することができますが、Xcodeの8はまだベータ版です。 Swift 2は、Xcode 7 Beta 4または5までは安定していませんでした。 –
@Codeこれはxcode8やswift3とは多分関係がありますが、 '[UInt8]'よりも 'Data'を優先的に使う方向次なる私の不満の主な原因は、イテレータが参照型オブジェクトの代わりに値型構造体として優れている理由です。 –