Vector
vector<T>は、Moveが提供する唯一のプリミティブコレクション型です。vector<T>は、値を「末尾」からプッシュ/ポップすることで拡大または縮小できるTの同質コレクションです。
vector<T>は任意のT型でインスタンス化出来ます。例えばvector<u64>、vector<address>、vector<0x42::MyModule::MyResource>、vector<vector<u8>>は全て有効なベクトル型です。
リテラル
一般的なベクターリテラル
vectorリテラルを使用して、任意の型のベクターを作成出来ます。
| 構文 | 型 | 説明 |
|---|---|---|
vector[] | Tが単一であるvector[]: vector<T>, 非参照型 | 空のベクター |
vector[e1, ..., en] | e_i: T s.t. 0 < i <= nでありn > 0であるvector[e1, ..., en]: vector<T> | (長さnの)n要素を持つベクター |
この場合、vectorの型は要素の型またはベクターの使用法から推測されます。 型を推測できない場合、または単にわかりやすくするため、型を明示的に指定出来ます。
vector<T>[]: vector<T>
vector<T>[e1, ..., en]: vector<T>
ベクターリテラルの例
script {
fun example() {
(vector[]: vector<bool>);
(vector[0u8, 1u8, 2u8]: vector<u8>);
(vector<u128>[]: vector<u128>);
(vector<address>[@0x42, @0x100]: vector<address>);
}
}
vector<u8>リテラル
Moveでのベクターの一般的な使用事例はvector<u8>で表される「バイト配列」を表す事です。これらの値は、公開鍵やハッシュ結果等の暗号化目的でよく使用されます。これらの値は非常に一般的なので、個々のu8値が数値形式で指定されるvector[]を使用するのとは対照的に、値をより読みやすくするための特定の構文が提供されています。
現在サポートされているvector<u8>リテラルの種類は、 バイト文字列 と 16進文字列 の2種類です。
バイト文字列
バイト文字列は、bで始まる引用符で囲まれた文字列リテ ラルです (例:b"Hello!\n")
これらはエスケープシーケンスを許可する ASCIIエンコードされた文字列です。現在サポートされているエスケープシーケンスは:
| エスケープシーケンス | 説明 |
|---|---|
\n | 改行 |
\r | キャリッジリターン |
\t | タブ |
\\ | バックスラッシュ |
\0 | ヌル |
\" | 引用 |
\xHH | 16進エスケープ、16進バイトシーケンスHHを挿入します |
16進文字列
16進文字列はxで始まる引用符で囲まれた文字列リテラルです (x例:x"48656C6C6F210A")
00からFFまでの各バイトペアは、16進数でエンコードされたu8値として解釈されます。従って、各バイトペアは、結果のvector<u8>内のひとつのエントリに対応します。
文字列リテラルの例
script {
fun byte_and_hex_strings() {
assert!(b"" == x"", 0);
assert!(b"Hello!\n" == x"48656C6C6F210A", 1);
assert!(b"\x48\x65\x6C\x6C\x6F\x21\x0A" == x"48656C6C6F210A", 2);
assert!(
b"\"Hello\tworld!\"\n \r \\Null=\0" ==
x"2248656C6C6F09776F726C6421220A200D205C4E756C6C3D00",
3
);
}
}
演算
以下に示すように、vectorはMove標準ライブラリのstd::vectorモジュールを介していくつかの演算を提供します。時間の経過で操作が追加される可能性が有ります。vectorの最新のドキュメントは、こちらで見つかります。
| 関数 | 説明 | 中止? |
|---|---|---|
vector::empty<T>(): vector<T> | T型の値を保存出来る空のベクターを作成します。 | 一度も無い |
vector::is_empty<T>(): bool | ベクトルvに要素がない場合はtrueを返し、そうでない場合はfalseを返します | 一度もない |
vector::singleton<T>(t: T): vector<T> | tを含むサイズ1のベクトルを作成する | 一度もない |
vector::length<T>(v: &vector<T>): u64 | ベクターvの長さを返す | 一度もない |
vector::push_back<T>(v: &mut vector<T>, t: T) | vの末尾へtを追加 | 一度もない |
vector::pop_back<T>(v: &mut vector<T>): T | vの最後の要素を削除して返す | vが空の場合 |
vector::borrow<T>(v: &vector<T>, i: u64): &T | インデックスiでTへの不変参照を返す | 境界内 でiがない場合 |
vector::borrow_mut<T>(v: &mut vector<T>, i: u64): &mut T | インデックスiでTへの可変参照を返す | 境界内でiがない場合 |
vector::destroy_empty<T>(v: vector<T>) | vを消去 | vが空でない場合 |
vector::append<T>(v1: &mut vector<T>, v2: vector<T>) | v1の末尾へv2の要素を追加します | 一度もない |
vector::reverse_append<T>(lhs: &mut vector<T>, other: vector<T>) | otherベクターの全ての要素をlhsベクター内へ逆順でプッシュする(otherで起きた時の逆順) | 一度もない |
vector::contains<T>(v: &vector<T>, e: &T): bool | eがベクトルv内にある場合はtrueを返します。そうでない場合はfalseを返します。 | 一度もない |
vector::swap<T>(v: &mut vector<T>, i: u64, j: u64) | ベクトルvのii番めとj番めのインデックスの要素を交換します。 | iまたはがj範囲外の場合 |
vector::reverse<T>(v: &mut vector<T>) | ベクトルv内の要素の順序を逆にする | 一度もない |
vector::reverse_slice<T>(v: &mut vector<T>, l: u64, r: u64) | ベクターv内の要素[l, r)の順序を逆で配置する | 一度もない |
vector::index_of<T>(v: &vector<T>, e: &T): (bool, u64) | eがイン デックスiのベクターvにある場合は(true, i)を返します。そうでない場合は(false, 0)を返します。 | 一度もない |
vector::insert<T>(v: &mut vector<T>, i: u64, e: T) | O(length - i)時間を使用して、0 <= i <= length位置へ新しい要素eを挿入します。 | iが範囲外の場合 |
vector::remove<T>(v: &mut vector<T>, i: u64): T | ベクターvのi番目の要素を削除し、後続の要素を全てシフトします。これは O(n) で、ベクター内の要素の順序は保持されます。 | iが範囲外の場合 |
vector::swap_remove<T>(v: &mut vector<T>, i: u64): T | ベクターvのi番目の要素を最後の要素と交換し、要素をポップします。これは O(1) ですが、ベクター内の要素の順序は保持されません | iが範囲外の場合 |
vector::trim<T>(v: &mut vector<T>, new_len: u64): u64 | ベクターvを小さいサイズのnew_lenへトリミングし、削除された要素を順に返します。 | new_lenはvの長さより大きい |
vector::trim_reverse<T>(v: &mut vector<T>, new_len: u64): u64 | ベクターvを小さいサイズのnew_lenへトリミングし、削除された要素を逆順で返します。 | new_lenはvの長さより大きい |
vector::rotate<T>(v: &mut vector<T>, rot: u64): u64 | rotate(&mut [1, 2, 3, 4, 5], 2) -> [3, 4, 5, 1, 2]を指定すると、分割 ポイント(この例では3)を返します。 | 一度もない |
vector::rotate_slice<T>(v: &mut vector<T>, left: u64, rot: u64, right: u64): u64 | rotate a slice [left, right) with left <= rot <= right in place, returns the split point left <= rot <= rightの位置でスライス[left, right)を回転し、分割点を返します。 | 一度もない |
例
script {
use std::vector;
let v = vector::empty<u64>();
vector::push_back(&mut v, 5);
vector::push_back(&mut v, 6);
assert!(*vector::borrow(&v, 0) == 5, 42);
assert!(*vector::borrow(&v, 1) == 6, 42);
assert!(vector::pop_back(&mut v) == 6, 42);
assert!(vector::pop_back(&mut v) == 5, 42);
}
ベクターの破壊とコピー
vector<T>の一部の動作は、要素型の機能Tに依存します。例えばdropを持たない要素を含むベクトルは、上記例のvのような暗黙的破棄が出来ません。vector::destroy_emptyで明白に破棄する必要が有ります。
注意:vecが要素を含んでいない場合を除きvector::destroy_emptyは実行時に中止します。
fun destroy_any_vector<T>(vec: vector<T>) {
vector::destroy_empty(vec) // この行を削除するとコンパイラエラーが発生します
}
ただし、dropの要素を含むベクターを削除してもエラーは発生しません。
script {
fun destroy_droppable_vector<T: drop>(vec: vector<T>) {
// 有効!
// ベクターを破棄するために何もする必要は有りません
}
}
ベクターは要素型がcopyを持たない限りコピーできません。言い換えると、Tが copyを持つ場合のみ、vector<T>はcopyを持ちます。
所有権
上記のように、要素がコピー出来る場合のみvector要素はコピー出来ます。