自己紹介
出田 守と申します。
しがない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
前回
前回はbool型とchar型について学びました。
Rust勉強中 - その7
型
タプル
タプルは様々な型の要素を持つことができる型です。
例
例 | 要素の型 |
---|---|
("left", "right") | ("&str", "&str") |
(0, 1) | ("i32", "i32") |
('0', 1) | ("char", "i32") |
('0', "1", (2, '3')) | ("char", "i32", "(i32, char)") |
(0,) | ("i32",) |
最後の例のようにカンマをタプルの末尾に追加しても良いです。また、**要素が一つだけのタプルを宣言する場合は、末尾にカンマを付けます。**これは、普通の括弧と区別するためです。
ユニット型
たまに関数で値を何も返さないけども、何か返さないといけない場合、ユニット型が用いられています。
ユニット型 |
---|
() |
例えば以下のような感じです。
fn open_some_file(path: &str) -> std::io::Result<()> {
let file = std::fs::File::open(path);
...
Ok(())
}
タプルのアクセス方法
タプルの要素へのアクセスにはちょっと癖があります。
タプルへのアクセスは必ずt.数値
である必要があります。
式 | 結果 |
---|---|
t.0 | 成功 |
t.-1 | エラー |
t.i | エラー |
t[i] | エラー |
ループなどで「i番目のタプル要素を参照」みたいなことはできないわけですね。注意が必要です。
また、タプルの中のタプル、例えば(0, 1, 2, (3, 4))
の3にアクセスしたい場合、(t.3).0
のようにアクセスします。
ポインタ型
ポインタ型はメモリのアドレスを指します。
参照
参照型はどこかの値のメモリアドレスを指し、&型
のように書きます(「&」を「レフ」と言う)。例えば、&i32
と書けば、i32型の参照となります。また、変数xへの参照&x
は、Rustでは「xへの参照を借用する」というようです。参照先の値を取り出すには*x
とします。これを参照解決といいます。
参照には(不変?)参照と可変参照があります。前者は変更不可能な参照で、後者は変更可能な参照です。
型 | 意味 |
---|---|
&T | 変更不可能な参照 |
&mut T | 変更可能な参照 |
fn print_ref_examples() {
println!("\n[print ref examples]");
let mut x = 0;
{
println!("<immutable ref>");
let y: &i32 = &x;
println!(" &x = {} {:p}", &x, &x);
println!(" y = {} {:p}", *y, y);
}
{
println!("<mutable ref>");
let y: &mut i32 = &mut x;
*y = 1;
println!(" y = {} {:p}", *y, y);
}
println!(" x = {}", x);
}
[print ref examples]
<immutable ref>
&x = 0 0x9beb7af514
&y = 0 0x9beb7af514
<mutable ref>
&mut y = 1 0x9beb7af514
x = 1
Box
Box型はヒープメモリ上に値を確保します。
ヒープにメモリを確保するにはBox::new
を使用します。
fn print_box_example() {
println!("\n[print box example]");
let b1 = Box::new(0);
let b2 = Box::new((0, '1', "2"));
println!("b1 = {} {}", b1, get_type(&b1));
println!("b2 = {:?} {}", b2, get_type(&b2));
}
[print box example]
b1 = 0 &alloc::boxed::Box<i32>
b2 = (0, '1', "2") &alloc::boxed::Box<(i32, char, &str)>
rawポインタ
Rustには、*const T
((不変)参照)と*mut T
(可変参照)のrawポインタ型があります。これらはRustが管理しないポインタなので、安全ではありません。つまり、rawポインタ型が指す先はnullかもしれないし、初期化されていないアドレス領域かもしれないということです。rawポインタ型の参照解決はunsafe
ブロック内で行う必要があります。
以下はunsafeブロック外で参照解決した場合エラーになりました。
fn print_raw_example() {
println!("\n[print raw example]");
let b = Box::new(0);
let unsafe_b: *mut i32 = Box::into_raw(b);
println!("b = {:?} {}", *unsafe_b, get_type(&unsafe_b));
}
$ cargo run
Compiling types v0.1.0 (C:\Users\deta\hack\rust\types)
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
--> src\main.rs:245:29
|
245 | println!("b = {:?} {}", *unsafe_b, get_type(&unsafe_b));
| ^^^^^^^^^ dereference of raw pointer
|
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
最後に使用したソースです。
...
fn print_tuple_examples() {
println!("\n[print tuple examples]");
println!("{:?} {:?}", ("left", "right"), (get_type("left"), get_type("right")));
println!("{:?} {:?}", (0, 1), (get_type(0), get_type(1)));
println!("{:?} {:?}", ('0', 1), (get_type('0'), get_type(1)));
println!("{:?} {:?}", ('0', "1", (2, '3')), (get_type('0'), get_type(1), get_type((2, '3'))));
println!("{:?} {:?}", (0,), (get_type(0),));
}
fn print_unit_example() {
fn open_some_file(path: &str) -> std::io::Result<()> {
std::fs::File::open(path);
Ok(())
}
println!("\n[print unit example]");
println!("{:?} {:?}", (), (get_type(())));
println!("open_some_file(\"secret.txt\")={:?}", open_some_file("secret.txt"));
}
fn print_tuple_access() {
let t = (0, 1, 2, (3, 4));
println!("\n[print tuple access]");
println!("t = {:?}", t);
println!("t.0 = {}", t.0);
println!("(t.3).0 = {}", (t.3).0);
// println!("t.3 = {}", t.3);
// let i = 0;
// println!("t.i = {}", t.i);
// println!("t[i] = {}", t[i]);
}
fn print_ref_examples() {
println!("\n[print ref examples]");
let mut x = 0;
{
println!("<immutable ref>");
let y: &i32 = &x;
println!(" &x = {} {:p}", &x, &x);
println!(" y = {} {:p}", *y, y);
}
{
println!("<mutable ref>");
let y: &mut i32 = &mut x;
*y = 1;
println!(" y = {} {:p}", *y, y);
}
println!(" x = {}", x);
}
fn print_box_example() {
println!("\n[print box example]");
let b1 = Box::new(0);
let b2 = Box::new((0, '1', "2"));
println!("b1 = {} {}", b1, get_type(&b1));
println!("b2 = {:?} {}", b2, get_type(&b2));
}
fn print_raw_example() {
println!("\n[print raw example]");
let b = Box::new(0);
let unsafe_b: *mut i32 = Box::into_raw(b);
unsafe {
println!("b = {:?} {}", *unsafe_b, get_type(&unsafe_b));
}
}
fn main() {
...
println!(">> Tuple type <<");
print_tuple_examples();
print_unit_example();
print_tuple_access();
println!(">> Pointer type <<");
print_ref_examples();
print_box_example();
print_raw_example();
}
$ cargo run
Compiling types v0.1.0 (C:\Users\deta\hack\rust\types)
Finished dev [unoptimized + debuginfo] target(s) in 0.76s
Running `target\debug\types.exe`
>> Tuple type <<
[print tuple examples]
("left", "right") ("&str", "&str")
(0, 1) ("i32", "i32")
('0', 1) ("char", "i32")
('0', "1", (2, '3')) ("char", "i32", "(i32, char)")
(0,) ("i32",)
[print unit example]
() "()"
open_some_file("secret.txt")=Ok(())
[print tuple access]
t = (0, 1, 2, (3, 4))
t.0 = 0
(t.3).0 = 3
>> Pointer type <<
[print ref examples]
<immutable ref>
&x = 0 0x56763ff954
y = 0 0x56763ff954
<mutable ref>
y = 1 0x56763ff954
x = 1
[print box example]
b1 = 0 &alloc::boxed::Box<i32>
b2 = (0, '1', "2") &alloc::boxed::Box<(i32, char, &str)>
[print raw example]
b = 0 &*mut i32
今回はここまで。