自己紹介
出田 守と申します。
しがないPythonプログラマです。
情報セキュリティに興味があり現在勉強中です。CTFやバグバウンティなどで腕を磨いています。主に低レイヤの技術が好きで、そっちばかり目が行きがちです。
Rustを勉強していくうえで、読んで学び、手を動かし、記録し、楽しく学んでいけたらと思います。
環境
新しい言語を学ぶということで、普段使わないWindowsとVimという新しい開発環境で行っています。
OS: Windows10 Home 64bit 1903
CPU: Intel Core i5-3470 @ 3.20GHz
Rust: 1.38.0
RAM: 8.00GB
Editor: Vim 8.1.1
Terminal: PowerShell
前回
前回はタプル型とポインタ型について学びました。
Rust勉強中 - その8
型
配列
配列は固定長で同じ型の要素を持つ型です。固定長のため拡大縮小や、サイズ以上の要素は持てません。
配列の生成方法
配列の生成方法は二つあります。
- [T; N]を型として指定。このときTは要素の型、Nは配列のサイズを表します。たとえば、
let a: [i32; 3]
とすると、変数aはi32型の要素を3つもつ配列を持つことを宣言します。 - [V; N]を式として指定。このときVは要素の値、Nは配列のサイズを表します。たとえば、
let a = [0; 8];
とすると変数aは0の値の要素を8つもつ配列を持ちます。
1.と2.の方法で以下に例を載せておきます。
fn print_array_access() {
println!("\n[print array access]");
let a: [i32; 3] = [0, 1, 2];
println!("a[0] = {}", a[0]);
// println!("a[-1] = {}", a[-1]); // error. usize only.
let i = 0;
println!("i={}; a[i] = {}", i, a[i]);
let b: [[i32; 3]; 1] = [a];
println!("b[0][0] = {}", b[0][0]);
let b = [[0;3]; 8];
println!("b = {:?} {}", b, get_type(b));
}
[print array example]
a = [0, 1, 2] [i32; 3]
b = [[0, 1, 2]] [[i32; 3]; 1]
a = [0, 0, 0, 0, 0, 0, 0, 0] [i32; 8]
b = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] [[i32; 3]; 8]
また、例にもあるように、2次元配列も生成できます。
配列の要素へのアクセス
要素へのアクセスはa[0]
のように行います。タプルと違ってインデックスにはa[i]
のように変数も指定できます。ただし、usizeしか指定できませんので-1などを指定するとエラーになります。
配列の要素の変更は変数宣言時ににmutを付けてa[0] = 1
などとすれば変更できます。
fn print_array_access() {
println!("\n[print array access]");
let mut a: [i32; 3] = [0, 1, 2];
println!("a[0] = {}", a[0]);
// println!("a[-1] = {}", a[-1]); // error. usize only.
let i = 0;
println!("i={}; a[i] = {}", i, a[i]);
a[i] = 1;
println!("a[i] = 1; a = {:?}", a);
let b: [[i32; 3]; 1] = [a];
println!("b[0][0] = {}", b[0][0]);
}
[print array access]
a[0] = 0
i=0; a[i] = 0
a[i] = 1; a = [1, 1, 2]
b[0][0] = 1
配列のメソッド
配列のメソッドはスライスと呼ばれる型のメソッドを呼び出しているので、スライスの節で書きます。
ベクタ
ベクタはヒープメモリに確保される可変の配列です。
ベクタの生成方法
- vec!マクロを使用
- Vec::new()を使用
- イテレータのメソッドcollectを使用
fn print_vector_example() {
println!("\n[print vector example]");
println!("vec![0, 1, 2] = {:?} {}", vec![0, 1, 2], get_type(vec![0, 1, 2]));
println!("vec![0; 3] = {:?} {}", vec![0; 3], get_type(vec![0; 3]));
let mut v: Vec<i32> = Vec::new();
// v.extend(&[0,1,2]);
println!("Vec::new() = {:?} {}", v, get_type(v.clone()));
let mut v: Vec<i32> = Vec::with_capacity(3);
// v.extend(&[0,1,2]);
println!("Vec::with_capacity(3) = {:?} {}", v, get_type(v.clone()));
let v: Vec<i32> = (0..3).collect();
println!("(0..3).collect() = {:?} {}", v, get_type(v.clone()));
println!("vec![vec![1; 2]; 3] = {:?} {}", vec![vec![1; 2]; 3], get_type(vec![vec![1; 2]; 3]));
}
[print vector example]
vec![0, 1, 2] = [0, 1, 2] alloc::vec::Vec<i32>
vec![0; 3] = [0, 0, 0] alloc::vec::Vec<i32>
Vec::new() = [] alloc::vec::Vec<i32>
Vec::with_capacity(3) = [] alloc::vec::Vec<i32>
(0..3).collect() = [0, 1, 2] alloc::vec::Vec<i32>
vec![vec![1; 2]; 3] = [[1, 1], [1, 1], [1, 1]] alloc::vec::Vec<alloc::vec::Vec<i32>>
vec!マクロは配列生成時のようにvec![V; N]
で同じ値VのサイズNのベクタが作れます。
ベクタのバッファサイズ
ベクタは3つの値で構成されているそうです。
- ヒープメモリ上のバッファへのポインタ
- バッファに保持できるサイズ
- 現在の要素数
もし、バッファの容量がいっぱいで、そこにさらに要素を追加した場合、新たにより大きなバッファが確保され、値をコピーし、古いバッファは解放されるそうです。このやり取りは無駄なので、もしサイズがあらかじめわかっている場合はVec::with_capacity
を用いるとそのサイズ分は確保されるので、わずかに効率が良いです。
len
メソッドで要素数を、capacity
メソッドでバッファに保持できるサイズを取得できます。
fn print_vector_capacity() {
println!("\n[print vector capacity]");
let mut v: Vec<i32> = Vec::with_capacity(3);
println!("v.len() = {}", v.len());
println!("v.capacity() = {}", v.capacity());
v.push(1);
println!("v.len() = {}", v.len());
println!("v.capacity() = {}", v.capacity());
}
[print vector capacity]
v.len() = 0
v.capacity() = 3
v.len() = 1
v.capacity() = 3
ベクタの要素へのアクセス
これは配列と同じなので省略します。
fn print_vector_access() {
println!("\n[print vector access]");
let v = vec![0, 1, 2];
println!("v[0] = {}", v[0]);
let i = 0;
println!("i={}; v[i] = {}", i, v[i]);
let v = vec![vec![1; 2]; 3];
println!("v[0][0] = {}", v[0][0]);
}
[print vector access]
v[0] = 0
i=0; v[i] = 0
v[0][0] = 1
ベクタのメソッド
fn print_vector_methods() {
println!("\n[print vector methods]");
let mut v = vec![0, 1, 2];
println!("v.push(1) = {:?}", {v.push(1); v.clone()});
println!("v.pop() = {:?} {:?}", v.pop(), v);
}
[print vector methods]
v.push(1) = [0, 1, 2, 1]
v.pop() = Some(1) [0, 1, 2]
もちろん、ベクタのメソッドはこれだけではなく便利なものがたくさんあります。
スライス
スライスは、配列やベクタなどのある位置を指し、[T]のように書きます。そして、常に参照されます。
スライスへの参照
スライスへの参照例を以下に示します。
fn print_slice_example() {
println!("\n[print slice example");
let a = [0, 1, 2];
let v = vec![0, 1, 2];
let sa: &[i32] = &a; // 配列への参照スライスへの参照(ややこしい笑)
let sv: &[i32] = &v; // ベクタへの参照スライスへの参照
println!("a = {:?} {}", a, get_type(a));
println!("v = {:?} {}", v, get_type(v.clone()));
println!("sa = {:?} {} {:p}", sa, get_type(sa), sa);
println!("sv = {:?} {} {:p}", sv, get_type(sv), sv);
}
[print slice example]
a = [0, 1, 2] [i32; 3]
v = [0, 1, 2] alloc::vec::Vec<i32>
sa = [0, 1, 2] &[i32] 0xe9836f8fc
sv = [0, 1, 2] &[i32] 0x1aa314ddbe0
fat pointer(ファットポインタ)
スライスにはfat pointerという構造があるそうです。
fat pointerには2つの値があります。
- スライスの最初の要素を指すポインタ
- スライスに含まれる要素数
fn print_slice_fat_pointer() {
println!("\n[print slice fat pointer]");
let a = [0, 1, 2];
let mut sa: &[i32] = &a;
println!("sa = {:?} {:p} {}", sa, sa, sa.len());
sa = &a[1..];
println!("sa = {:?} {:p} {}", sa, sa, sa.len());
}
[print slice fat pointer]
sa = [0, 1, 2] 0x60b936f98c 3
sa = [1, 2] 0x60b936f990 2
スライスの参照先の要素へのアクセス
スライスを使うことで、ベクタや配列に関係なく同じように要素へアクセスできます。
fn print_slice_access() {
println!("\n[print slice access]");
let a = [0, 1, 2];
let v = vec![0, 1, 2];
let sa: &[i32] = &a;
let sv: &[i32] = &v;
println!("sa = {:?} {} {:p}", sa, get_type(sa), sa);
println!("sv = {:?} {} {:p}", sv, get_type(sv), sv);
println!("sa[0] = {:?} {} {:p}", &sa[0], get_type(&sa[0]), &sa[0]);
println!("sv[0] = {:?} {} {:p}", &sv[0], get_type(&sa[0]), &sv[0]);
println!("sa[0..2] = {:?} {} {:p}", &sa[0..2], get_type(&sa[0..2]), &sa[0..2]);
println!("sv[0..2] = {:?} {} {:p}", &sv[0..2], get_type(&sv[0..2]), &sv[0..2]);
println!("sa[1] = {:?} {} {:p}", &sa[1], get_type(&sa[1]), &sa[1]);
println!("sv[1] = {:?} {} {:p}", &sv[1], get_type(&sa[1]), &sv[1]);
println!("sa[1..2] = {:?} {} {:p}", &sa[1..2], get_type(&sa[1..2]), &sa[1..2]);
println!("sv[1..2] = {:?} {} {:p}", &sv[1..2], get_type(&sv[1..2]), &sv[1..2]);
}
[print slice example]
a = [0, 1, 2] [i32; 3]
v = [0, 1, 2] alloc::vec::Vec<i32>
sa = [0, 1, 2] &[i32] 0xce487df4ac
sv = [0, 1, 2] &[i32] 0x2645419db40
[print slice access]
sa = [0, 1, 2] &[i32] 0xce487def54
sv = [0, 1, 2] &[i32] 0x2645419dbe0
sa[0] = 0 &i32 0xce487def54
sv[0] = 0 &i32 0x2645419dbe0
sa[0..2] = [0, 1] &[i32] 0xce487def54
sv[0..2] = [0, 1] &[i32] 0x2645419dbe0
sa[1] = 1 &i32 0xce487def58
sv[1] = 1 &i32 0x2645419dbe4
sa[1..2] = [1] &[i32] 0xce487def58
sv[1..2] = [1] &[i32] 0x2645419dbe4
また、アドレスをみると、1番目の要素を指したときに4byte増えて次の要素を指しているのが分かります。
スライスのメソッド
スライスのメソッドの一部例を以下に載せておきます。他にも便利なメソッドはたくさんあるので必要に応じて参照していきたいですね!
fn print_slice_methods() {
println!("\n[print slice methods]");
let sa: &mut [i32] = &mut [9, 3, 1, 5, 7, 2];
println!("sa = {:?} {}", &sa[1..3], get_type(&sa));
println!("sa.len() = {}", sa.len());
println!("sa.sort() = {:?}", {sa.sort(); sa});
println!("[0, 1, 2].to_vec() = {:?} {}", &[0, 1, 2].to_vec(), get_type(&[0, 1, 2].to_vec()));
println!("[\"Hello,\", \"world!\"].join(\"\\t\") = {}", ["Hello,", "world!"].join("\t"));
println!("&[0, 1, 2].iter() = {:?} {}", &[0, 1, 2].iter(), get_type(&[0, 1, 2].iter()));
}
[print slice methods]
sa = [3, 1] &&mut [i32]
sa.len() = 6
sa.sort() = [1, 2, 3, 5, 7, 9]
[0, 1, 2].to_vec() = [0, 1, 2] &alloc::vec::Vec<i32>
["Hello,", "world!"].join("\t") = Hello, world!
&[0, 1, 2].iter() = Iter([0, 1, 2]) &core::slice::Iter<i32>
今回使用したソース
...
fn print_array_example() {
println!("\n[print array example]");
let a: [i32; 3] = [0, 1, 2];
println!("a = {:?} {}", a, get_type(a));
let b: [[i32; 3]; 1] = [a];
println!("b = {:?} {}", b, get_type(b));
let a = [0; 8];
println!("a = {:?} {}", a, get_type(a));
let b = [[0;3]; 8];
println!("b = {:?} {}", b, get_type(b));
}
fn print_array_access() {
println!("\n[print array access]");
let mut a: [i32; 3] = [0, 1, 2];
println!("a[0] = {}", a[0]);
// println!("a[-1] = {}", a[-1]); // error. usize only.
let i = 0;
println!("i={}; a[i] = {}", i, a[i]);
a[i] = 1;
println!("a[i] = 1; a = {:?}", a);
let b: [[i32; 3]; 1] = [a];
println!("b[0][0] = {}", b[0][0]);
}
fn print_vector_example() {
println!("\n[print vector example]");
println!("vec![0, 1, 2] = {:?} {}", vec![0, 1, 2], get_type(vec![0, 1, 2]));
println!("vec![0; 3] = {:?} {}", vec![0; 3], get_type(vec![0; 3]));
let mut v: Vec<i32> = Vec::new();
// v.extend(&[0,1,2]);
println!("Vec::new() = {:?} {}", v, get_type(v.clone()));
let mut v: Vec<i32> = Vec::with_capacity(3);
// v.extend(&[0,1,2]);
println!("Vec::with_capacity(3) = {:?} {}", v, get_type(v.clone()));
let v: Vec<i32> = (0..3).collect();
println!("(0..3).collect() = {:?} {}", v, get_type(v.clone()));
println!("vec![vec![1; 2]; 3] = {:?} {}", vec![vec![1; 2]; 3], get_type(vec![vec![1; 2]; 3]));
}
fn print_vector_capacity() {
println!("\n[print vector capacity]");
let mut v: Vec<i32> = Vec::with_capacity(3);
println!("v.len() = {}", v.len());
println!("v.capacity() = {}", v.capacity());
v.push(1);
println!("v.len() = {}", v.len());
println!("v.capacity() = {}", v.capacity());
}
fn print_vector_access() {
println!("\n[print vector access]");
let v = vec![0, 1, 2];
println!("v[0] = {}", v[0]);
let i = 0;
println!("i={}; v[i] = {}", i, v[i]);
let v = vec![vec![1; 2]; 3];
println!("v[0][0] = {}", v[0][0]);
}
fn print_vector_methods() {
println!("\n[print vector methods]");
let mut v = vec![0, 1, 2];
println!("v.push(1) = {:?}", {v.push(1); v.clone()});
println!("v.pop() = {:?} {:?}", v.pop(), v);
}
fn print_slice_example() {
println!("\n[print slice example]");
let a = [0, 1, 2];
let v = vec![0, 1, 2];
let sa: &[i32] = &a;
let sv: &[i32] = &v;
println!("a = {:?} {}", a, get_type(a));
println!("v = {:?} {}", v, get_type(v.clone()));
println!("sa = {:?} {} {:p}", sa, get_type(sa), sa);
println!("sv = {:?} {} {:p}", sv, get_type(sv), sv);
}
fn print_slice_fat_pointer() {
println!("\n[print slice fat pointer]");
let a = [0, 1, 2];
let mut sa: &[i32] = &a;
println!("sa = {:?} {:p} {}", sa, sa, sa.len());
sa = &a[1..];
println!("sa = {:?} {:p} {}", sa, sa, sa.len());
}
fn print_slice_access() {
println!("\n[print slice access]");
let a = [0, 1, 2];
let v = vec![0, 1, 2];
let sa: &[i32] = &a;
let sv: &[i32] = &v;
println!("sa = {:?} {} {:p}", sa, get_type(sa), sa);
println!("sv = {:?} {} {:p}", sv, get_type(sv), sv);
println!("sa[0] = {:?} {} {:p}", &sa[0], get_type(&sa[0]), &sa[0]);
println!("sv[0] = {:?} {} {:p}", &sv[0], get_type(&sv[0]), &sv[0]);
println!("sa[0..2] = {:?} {} {:p}", &sa[0..2], get_type(&sa[0..2]), &sa[0..2]);
println!("sv[0..2] = {:?} {} {:p}", &sv[0..2], get_type(&sv[0..2]), &sv[0..2]);
println!("sa[1] = {:?} {} {:p}", &sa[1], get_type(&sa[1]), &sa[1]);
println!("sv[1] = {:?} {} {:p}", &sv[1], get_type(&sv[1]), &sv[1]);
println!("sa[1..2] = {:?} {} {:p}", &sa[1..2], get_type(&sa[1..2]), &sa[1..2]);
println!("sv[1..2] = {:?} {} {:p}", &sv[1..2], get_type(&sv[1..2]), &sv[1..2]);
}
fn print_slice_methods() {
println!("\n[print slice methods]");
let sa: &mut [i32] = &mut [9, 3, 1, 5, 7, 2];
println!("sa = {:?} {}", &sa[1..3], get_type(&sa));
println!("sa.len() = {}", sa.len());
println!("sa.sort() = {:?}", {sa.sort(); sa});
println!("[0, 1, 2].to_vec() = {:?} {}", &[0, 1, 2].to_vec(), get_type(&[0, 1, 2].to_vec()));
println!("[\"Hello,\", \"world!\"].join(\"\\t\") = {}", ["Hello,", "world!"].join("\t"));
println!("&[0, 1, 2].iter() = {:?} {}", &[0, 1, 2].iter(), get_type(&[0, 1, 2].iter()));
}
fn main() {
...
println!(">> Array type <<");
print_array_example();
print_array_access();
println!(">> Vector type <<");
print_vector_example();
print_vector_capacity();
print_vector_access();
print_vector_methods();
println!(">> Slice type <<");
print_slice_example();
print_slice_fat_pointer();
print_slice_access();
print_slice_methods();
}
>> Array type <<
[print array example]
a = [0, 1, 2] [i32; 3]
b = [[0, 1, 2]] [[i32; 3]; 1]
a = [0, 0, 0, 0, 0, 0, 0, 0] [i32; 8]
b = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] [[i32; 3]; 8]
[print array access]
a[0] = 0
i=0; a[i] = 0
a[i] = 1; a = [1, 1, 2]
b[0][0] = 1
>> Vector type <<
[print vector example]
vec![0, 1, 2] = [0, 1, 2] alloc::vec::Vec<i32>
vec![0; 3] = [0, 0, 0] alloc::vec::Vec<i32>
Vec::new() = [] alloc::vec::Vec<i32>
Vec::with_capacity(3) = [] alloc::vec::Vec<i32>
(0..3).collect() = [0, 1, 2] alloc::vec::Vec<i32>
vec![vec![1; 2]; 3] = [[1, 1], [1, 1], [1, 1]] alloc::vec::Vec<alloc::vec::Vec<i32>>
[print vector capacity]
v.len() = 0
v.capacity() = 3
v.len() = 1
v.capacity() = 3
[print vector access]
v[0] = 0
i=0; v[i] = 0
v[0][0] = 1
[print vector methods]
v.push(1) = [0, 1, 2, 1]
v.pop() = Some(1) [0, 1, 2]
>> Slice type <<
[print slice example]
a = [0, 1, 2] [i32; 3]
v = [0, 1, 2] alloc::vec::Vec<i32>
sa = [0, 1, 2] &[i32] 0xc597aff5ac
sv = [0, 1, 2] &[i32] 0x1f4476ad690
[print slice fat pointer]
sa = [0, 1, 2] 0xc597aff6ec 3
sa = [1, 2] 0xc597aff6f0 2
[print slice access]
sa = [0, 1, 2] &[i32] 0xc597aff0f4
sv = [0, 1, 2] &[i32] 0x1f4476ad5d0
sa[0] = 0 &i32 0xc597aff0f4
sv[0] = 0 &i32 0x1f4476ad5d0
sa[0..2] = [0, 1] &[i32] 0xc597aff0f4
sv[0..2] = [0, 1] &[i32] 0x1f4476ad5d0
sa[1] = 1 &i32 0xc597aff0f8
sv[1] = 1 &i32 0x1f4476ad5d4
sa[1..2] = [1] &[i32] 0xc597aff0f8
sv[1..2] = [1] &[i32] 0x1f4476ad5d4
[print slice methods]
sa = [3, 1] &&mut [i32]
sa.len() = 6
sa.sort() = [1, 2, 3, 5, 7, 9]
[0, 1, 2].to_vec() = [0, 1, 2] &alloc::vec::Vec<i32>
["Hello,", "world!"].join("\t") = Hello, world!
&[0, 1, 2].iter() = Iter([0, 1, 2]) &core::slice::Iter<i32>
今回はここまで~。