M.Hiroi's Home Page

Linux Programming

お気楽 Rust プログラミング超入門

[ Home | Linux | Rust ]

Rust の基礎知識

●ポインタの基本

リスト : ポインタの簡単な使用例

struct Foo {
    nums: i32
}

impl Drop for Foo {
    fn drop(&mut self) {
        println!("drop foo {}", self.nums);
    }
}

fn main() {
    let x = 123;
    let raw_x = &x as *const i32;
    let ref_x;
    println!("{:p}", raw_x);   // :p はポインタ (アドレス) を表示する
    unsafe {
        ref_x = &*raw_x;
        println!("{}", *raw_x);
    }
    println!("{}", ref_x);

    let mut y = 456;
    let raw_y = &y as *const i32;
    let raw_mut_y = &mut y as *mut i32;
    let raw_mut_y1 = &mut y as *mut i32;
    println!("{:p}", raw_y);
    println!("{:p}", raw_mut_y);
    println!("{:p}", raw_mut_y1);
    let ref_mut_y;                 // let mut ... とするとワーニング (mut は不要)
    unsafe {
        println!("{}", *raw_y);
        *raw_mut_y = 999;
        println!("{}", *raw_y);
        *raw_mut_y1 = 9999;
        println!("{}", *raw_y);
        ref_mut_y = &mut *raw_mut_y;
    }
    *ref_mut_y = 10000;
    println!("{}", y);

    let mut z = Foo { nums: 1000 };
    let raw_z = &z as *const Foo;
    let raw_mut_z = &mut z as *mut Foo;
    unsafe {
        println!("{}", (*raw_z).nums);
        // let a = *raw_z; raw pointer から move はできない
        // println!("{}", a.nums);
        *raw_mut_z = Foo { nums: 2000 };
        println!("{}", (*raw_z).nums);
    }
}
0x7fffc32f49d8
123
123
0x7fffc32f49dc
0x7fffc32f49dc
0x7fffc32f49dc
456
999
9999
10000
1000
drop foo 1000
2000
drop foo 2000
リスト : offset() の簡単な使用例

fn main() {
    let a = [1, 2, 3, 4, 5, 6, 7, 8];
    let raw_a = &a[0] as *const i32;
    println!("{:p}", raw_a);
    unsafe {
        for i in 0 .. 8 {
            print!("{} ", *raw_a.offset(i));
        }
        println!("");
    }
    let mut b = vec![1, 2, 3, 4, 5, 6, 7, 8];
    let mut raw_b = &mut b[0] as *mut i32;
    println!("{:p}", raw_b);
    unsafe {
        for _ in 0 .. 8 {
            *raw_b *= 10;
            print!("{} ", *raw_b);
            raw_b = raw_b.offset(1)
        }
        println!("");
    }
}
0x7fffdc93fef8
1 2 3 4 5 6 7 8
0x7fffd43b4510
10 20 30 40 50 60 70 80
リスト : Box と生ポインタの使用例

struct Foo {
    nums: i32
}

impl Drop for Foo {
    fn drop(&mut self) {
        println!("drop foo {}", self.nums);
    }
}

fn main() {
    let a = Box::new(Foo { nums: 123 });
    let raw_a = &*a as *const Foo;
    unsafe {
        println!("{}", (*raw_a).nums);
    }
    let mut b = Box::new(Foo { nums: 456 });
    let raw_mut_b = &mut *b as *mut Foo;
    unsafe {
        println!("{}", (*raw_mut_b).nums);
        *raw_mut_b = Foo { nums: 789 };
        println!("{}", (*raw_mut_b).nums);
    }
    let c = Box::new(Foo { nums: 1000 });
    let raw_mut_c = Box::into_raw(c);
    unsafe {
        println!("{}", (*raw_mut_c).nums);
        drop(Box::from_raw(raw_mut_c));
        // drop(raw_mut_c);  NG
        // std::ptr::drop_in_place(raw_mut_c);  OK
    }
}
123
456
drop foo 456
789
1000
drop foo 1000
drop foo 789
drop foo 123

●マクロの基本

リスト : マクロの簡単な使用例 (1)

macro_rules! foo {
    ($a:expr) => (println!("{:?} = {:?}", stringify!($a), $a));
}

macro_rules! bar {
    () => (println!("[]"));
    ($a:expr) => (println!("{:?}", [$a]));
    ($a:expr, $b:expr) => (println!("{:?}", [$a, $b]));
    ($a:expr, $b:expr, $c:expr) => (println!("{:?}", [$a, $b, $c]));
}

fn main() {
    foo!(1 + 2);
    foo![11 * 12];
    foo!{100 - 200};
    // foo!(); コンパイルエラー
    bar!();
    bar!(1);
    bar!(1,2);
    bar!(1,2,3);
}
"1 + 2" = 3
"11 * 12" = 132
"100 - 200" = -100
[]
[1]
[1, 2]
[1, 2, 3]
リスト : マクロの簡単な使用例 (2)

macro_rules! sum {
    () => (0);
    ($($x:expr),+) => ({
        let mut acc = 0;
        $( acc += $x; )+
        acc
    });
}

fn main() {
    println!("{}", sum!());
    println!("{}", sum!(1));
    println!("{}", sum!(1, 2, 3, 4, 5));
}
0
1
15
リスト : マクロの簡単な例題

use std::cell::RefCell;

// 遅延評価
struct Delay<'a, T: 'a> {
    value: RefCell<Option<T>>,
    func: Box<dyn Fn() -> T + 'a>
}

impl<'a, T: 'a> Delay<'a, T> {
    fn new<F: 'a>(f: F) -> Delay<'a, T> where F: Fn() -> T {
        Delay { func: Box::new(f), value: RefCell::new(None) }
    }
    fn force(&self) -> &T {
        let mut val = self.value.borrow_mut();
        if val.is_none() {
            *val = Some((self.func)());
        }
        match unsafe { self.value.as_ptr().as_ref().unwrap() } {
            &Some(ref x) => x,
            _ => unreachable!()
        }
    }
}

// Delay を生成するマクロ
// delay! を定義することで使いやすくなる
macro_rules! delay {
    ($e:expr) => (Delay::new(move || $e));
}

// たらいまわし関数
fn tarai(x: i32, y: i32, z: Delay<i32>) -> i32 {
    if x <= y {
        y
    } else {
        let zz = *z.force();
        tarai(tarai(x - 1, y, z),
              tarai(y - 1, zz, delay!(x)),
              delay!(tarai(zz - 1, x, delay!(y))))
    }
}

fn main() {
    let a = delay!({println!("oops"); 1 + 2});  // ブロックも式
    println!("{}", a.force()); 
    println!("{}", a.force());
    println!("{}", tarai(14, 7, delay!(0)));
    println!("{}", tarai(140, 70, delay!(0)));
}
oops
3
3
14
140

●ライフタイム境界

リスト : ライフタイム境界の簡単な例 (1)

struct Foo<'a, T: 'a> {
    value: &'a T
}

impl<'a, T> Foo<'a, T> {
    fn new(val: &'a T) -> Foo<'a, T> {
        Foo { value: val }
    }
}

fn main() {
    let x = 10;
    let a = Foo::new(&x);
    println!("{}", a.value);

    //let b: Foo<i32>;
    //{
    //    let y = 20;  コンパイルエラー `y` does not live long enough
    //    b = Foo::new(&y);
    //}
}
10
リスト : ライフタイム境界の簡単な例 (2)

use std::cell::RefCell;

// 遅延評価
struct Delay<'a, T: 'a> {
    value: RefCell<Option<T>>,
    func: Box<dyn Fn() -> T + 'a>
}

impl<'a, T: 'a> Delay<'a, T> {
    fn new<F: 'a>(f: F) -> Delay<'a, T> where F: Fn() -> T {
        Delay { func: Box::new(f), value: RefCell::new(None) }
    }
    fn force(&self) -> &T {
        let mut val = self.value.borrow_mut();
        if val.is_none() {
            *val = Some((self.func)());
        }
        match unsafe { self.value.as_ptr().as_ref().unwrap() } {
            &Some(ref x) => x,
            _ => unreachable!()
        }
    }
}

●Copy と Clone

リスト : Copy と Clone トレイト

#[derive(Debug)]
struct Foo {
    num: i32
}

#[derive(Debug, Copy, Clone)]
struct Bar {
    num: i32
}

#[derive(Debug, Copy, Clone)]
struct Baz<T> {
    item: T
}

fn main() {
    let a = Foo { num: 123 };
    let mut b = a;            // 所有権の移動
    b.num += 1000;
    // println!("{:?}", a);      コンパイルエラー
    println!("{:?}", b);
    let c = Bar { num: 456 };
    let mut d = c;            // コピー
    d.num += 1000; 
    println!("{:?}", c);      // 所有権は移動しないのでアクセスできる
    println!("{:?}", d);

    let e = Baz { item: Foo { num: 123 } };
    let f = e;      // 所有権の移動
    // println!("{:?}", e);   コンパイルエラー
    println!("{:?}", f);
    println!("{}", f.item.num);

    let g = Baz { item: Bar { num: 456 } };
    let h = g;      // コピー
    println!("{:?}", g);
    println!("{:?}", h);
}
Foo { num: 1123 }
Bar { num: 456 }
Bar { num: 1456 }
Baz { item: Foo { num: 123 } }
123
Baz { item: Bar { num: 456 } }
Baz { item: Bar { num: 456 } }

●トランスミュート (transmute)

リスト : transmute() の簡単な使用例

use std::mem::transmute;

fn main() {
    unsafe {
        // transmute() はビットパターンでの変換になる
        println!("{:X}", transmute::<f64, u64>(1.2345));
        println!("{:X}", transmute::<f32, u32>(1.2345));

        // u8 の配列を数値に変換するときはエンディアンに注意
        let a: [u8; 4] = [0x19, 0x04, 0x9e, 0x3f];
        println!("{:X}", transmute::<[u8; 4], u32>(a));
        println!("{}", transmute::<[u8; 4], f32>(a));
        println!("{:?}", transmute::<i32, [u8; 4]>(0x12345678));
    }
}
3FF3C083126E978D
3F9E0419
3F9E0419
1.2345
[120, 86, 52, 18]

●Hash

リスト : トレイト Hash の簡単な使用例

use std::collections::HashSet;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

#[derive(Hash, PartialEq, Eq)]
struct Foo {
    num: i32
}

fn main() {
    let mut h: HashSet<Foo> = HashSet::new();
    for i in 0 .. 10 {
        h.insert(Foo { num: i });
    }
    println!("{}", h.contains(&Foo { num: 0 }));
    println!("{}", h.contains(&Foo { num: 9 }));
    println!("{}", h.contains(&Foo { num: 10 }));

    for i in 0 .. 10 {
        let mut hasher: DefaultHasher = DefaultHasher::new();
        let a = Foo { num: i };
        a.hash(&mut hasher);
        println!("{}", hasher.finish());
    }
}
true
true
false
14709398186846620400
1742378985846435984
16336925911988107921
568126464209439262
15565210526001683492
14828406784900857967
2748490571820495779
13916993215237271530
17499417595158719687
16856616568243533183

●Default

リスト : Default トレイトの簡単な使用例

#[derive(Debug, Default)]
struct Foo {
    x: i32,
    y: f64
}

#[derive(Debug)]
struct Bar {
    x: i32,
    y: f64
}

impl Default for Bar {
    fn default() -> Bar {
        Bar { x: 12345, y: 1.2345}
    }
}

fn main() {
    let a: i32 = Default::default();
    let b: f64 = Default::default();
    let c: Foo = Default::default();
    let d: Bar = Default::default();
    println!("{}", a);
    println!("{}", b);
    println!("{}", c.x);
    println!("{}", c.y);
    println!("{}", d.x);
    println!("{}", d.y);
}
0
0
0
0
12345
1.2345

●UnsafeCell<T>

リスト : UnsafeCell の簡単な使用例

use std::cell::UnsafeCell;

#[derive(Debug)]
struct Foo {
    x: i32, y: i32
}

fn main() {
    let a = UnsafeCell::new(123);
    let p = a.get();
    unsafe {
        println!("{}", *p);
        *p = 456;
        println!("{}", *p);
    }

    let b = UnsafeCell::new(Foo { x: 10, y: 20 });
    let q = b.get();
    unsafe {
        println!("{}", (*q).x);
        println!("{}", (*q).y);
        (*q).x = 123;
        (*q).y = 456;
        println!("{}", (*q).x);
        println!("{}", (*q).y);
        let b1 = b.into_inner();
        println!("{:?}", b1);
    }

    let c = UnsafeCell::new(Box::new(Foo { x: 10, y: 20 }));
    let r = c.get();
    unsafe {
        println!("{}", (*r).x);
        println!("{}", (*r).y);
        (*r).x = 123;
        (*r).y = 456;
        println!("{}", (*r).x);
        println!("{}", (*r).y);
        let c1 = c.into_inner();
        println!("{:?}", c1);
    }
}
123
456
10
20
123
456
Foo { x: 123, y: 456 }
10
20
123
456
Foo { x: 123, y: 456 }

●Ref<T> と RefMut<T>

リスト : Ref と RefMut の簡単な使用例

use std::cell::{RefCell, Ref, RefMut};

#[derive(Debug)]
struct Foo {
    x: i32, y: f64
}

fn main() {
    let a = RefCell::new(Foo { x: 100, y: 1.2345 });
    {
        let p = Ref::map(a.borrow(), |foo| &foo.x);
        let q = Ref::clone(&p);
        println!("{}", *p);
        println!("{}", *q);
    }
    {
        let mut r = RefMut::map(a.borrow_mut(), |foo| &mut foo.y);
        *r *= 10.0;
    }
    println!("{:?}", a); 
}
100
100
RefCell { value: Foo { x: 100, y: 12.344999999999999 } }

●BinaryHeap<T>

リスト : BinaryHeap の簡単な使用例

use std::collections::BinaryHeap;
use std::cmp::Ordering;

#[derive(Debug, PartialEq, Eq)]
struct Foo {
    num: i32
}

impl Ord for Foo {
    fn cmp(&self, other: &Foo) -> Ordering {
        self.num.cmp(&other.num).reverse()
    }
}

impl PartialOrd for Foo {
    fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn main() {
    let a = [5,6,4,3,7,8,2,1,9];
    let mut q1 = BinaryHeap::new();
    let mut q2 = BinaryHeap::new();
    for x in &a {
        q1.push(*x);
        q2.push( Foo { num: *x });
    }
    while !q1.is_empty() {
        println!("{:?}", q1.pop());
    }
    while !q2.is_empty() {
        println!("{:?}", q2.pop());
    }
}
Some(9)
Some(8)
Some(7)
Some(6)
Some(5)
Some(4)
Some(3)
Some(2)
Some(1)
Some(Foo { num: 1 })
Some(Foo { num: 2 })
Some(Foo { num: 3 })
Some(Foo { num: 4 })
Some(Foo { num: 5 })
Some(Foo { num: 6 })
Some(Foo { num: 7 })
Some(Foo { num: 8 })
Some(Foo { num: 9 })

初版 2017 年 9 - 12 月
改訂 2022 年 7 月 30 日

Copyright (C) 2017-2022 Makoto Hiroi
All rights reserved.

[ Home | Linux | Rust ]