5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rust勉強中 - その8 -> タプルとポインタ型

Last updated at Posted at 2019-10-01

自己紹介

出田 守と申します。
しがない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",)

最後の例のようにカンマをタプルの末尾に追加しても良いです。また、**要素が一つだけのタプルを宣言する場合は、末尾にカンマを付けます。**これは、普通の括弧と区別するためです。

ユニット型

たまに関数で値を何も返さないけども、何か返さないといけない場合、ユニット型が用いられています。

ユニット型
()

例えば以下のような感じです。

main.rs
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

今回はここまで。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?