M.Hiroi's Home Page

Linux Programming

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

[ Home | Linux | Rust ]

Rust の基礎知識

●演算子の多重定義

リスト : トレイト Add の定義

pub trait Add<RHS = Self> {
    type Output;
    fn add(self, rhs: RHS) -> Self::Output;
}
リスト : 演算子の多重定義

use std::ops::Add;

#[derive(Debug, Copy, Clone)]
struct Point {
    x: f64, y: f64
}

#[derive(Debug, Copy, Clone)]
struct Point3d {
    x: f64, y: f64, z: f64
}

impl Point {
    fn new(x0: f64, y0: f64) -> Point {
        Point { x: x0, y: y0 }
    }
}

impl Point3d {
    fn new(x0: f64, y0: f64, z0: f64) -> Point3d {
        Point3d { x: x0, y: y0, z: z0 }
    }
}

// 左辺と右辺でデータ型が同じ場合
impl Add for Point {
    type Output = Point;
    fn add(self, other: Point) -> Point {
        Point {
             x: self.x + other.x,
             y: self.y + other.y
        }
    }
}

impl Add for Point3d {
    type Output = Point3d;
    fn add(self, other: Point3d) -> Point3d {
        Point3d {
             x: self.x + other.x,
             y: self.y + other.y,
             z: self.z + other.z
        }
    }
}

// 右辺と左辺でデータ型が違う場合
impl Add<Point3d> for Point {
    type Output = Point3d;
    fn add(self, other: Point3d) -> Point3d {
        Point3d {
            x: self.x + other.x,
            y: self.y + other.y,
            z: other.z
        }
    }
}

impl Add<Point> for Point3d {
    type Output = Point3d;
    fn add(self, other: Point) -> Point3d {
        Point3d {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z
        }
    }
}

fn main() {
    let p1 = Point::new(1.0, 1.0);
    let p2 = Point::new(2.0, 2.0);
    let p3 = Point3d::new(10.0, 10.0, 10.0);
    let p4 = Point3d::new(20.0, 20.0, 20.0);
    println!("{:?}", p1 + p2);
    println!("{:?}", p3 + p4);
    println!("{:?}", p1 + p3);
    println!("{:?}", p4 + p2);
}
Point { x: 3, y: 3 }
Point3d { x: 30, y: 30, z: 30 }
Point3d { x: 11, y: 11, z: 10 }
Point3d { x: 22, y: 22, z: 20 }

●サイズ不定型

リスト : サイズ不定型の簡単な使用例

struct Foo<T: ?Sized> {
    buff: T      // 大きさが異なる配列でも格納できる
}

fn main() {
    let a = [1,2,3];
    let b = [1,2,3,4,5,6];
    let c = Foo { buff: a };
    let d = Foo { buff: b };
    let e = Foo { buff: [1,2,3,4,5,6,7,8,9]};
    println!("{:?}", c.buff);
    println!("{:?}", d.buff);
    println!("{:?}", e.buff);
}
[1, 2, 3]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

●Deref

リスト : トレイト Deref の定義

pub trait Deref {
    type Target: ?Sized;
    fn deref(&self) -> &Self::Target;
}
リスト : トレイト Deref の簡単な使用例

use std::ops::Deref;

struct Foo<T: ?Sized> {
    buff: T
}

impl<T> Deref for Foo<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.buff
    }
}

struct Bar {
    num: i32
}

impl Deref for Bar {
    type Target = i32;
    fn deref(&self) -> &i32 {
        &self.num
    }
}

fn main() {
    let a = Foo { buff: [1,2,3] };
    let b = Foo { buff: [4,5,6,7,8,9] };
    let c = Bar { num: 123 };
    let d = Bar { num: 456 };
    println!("{:?}", *a);
    println!("{:?}", *b);
    println!("{:?}", *c);
    println!("{:?}", *d);
}
[1, 2, 3]
[4, 5, 6, 7, 8, 9]
123
456
リスト : トレイト DerefMut

pub trait DerefMut: Deref {
    fn deref_mut(&mut self) -> &mut Self::Target;
}
リスト : DerefMut の簡単な使用例

use std::ops::{Deref, DerefMut};

struct Bar {
    num: i32
}

impl Deref for Bar {
    type Target = i32;
    fn deref(&self) -> &i32 {
        &self.num
    }
}

impl DerefMut for Bar {
    fn deref_mut(&mut self) -> &mut i32 {
        &mut self.num
    } 
}

fn main() {
    let mut c = Bar { num: 123 };
    let d = Bar { num: 456 };
    println!("{:?}", *c);
    println!("{:?}", *d);
    *c = 789;
    println!("{:?}", *c);
}
123
456
789

●型強制

リスト : deref の型強制

use std::ops::{Deref, DerefMut};

struct Bar {
    num: i32
}

impl Deref for Bar {
    type Target = i32;
    fn deref(&self) -> &i32 {
        &self.num
    }
}

impl DerefMut for Bar {
    fn deref_mut(&mut self) -> &mut i32 {
        &mut self.num
    } 
}

fn bar(x: &i32) {
    println!("{}", x);
}

fn main() {
    let mut c = Bar { num: 123 };
    let d = Bar { num: 456 };
    println!("{:?}", *c);
    println!("{:?}", *d);
    *c = 789;
    println!("{:?}", *c);
    bar(&c);
    bar(&d);
    let e = Box::new(1000);
    bar(&e);
    let f = Box::new(Bar { num: 2000 });
    bar(&f);
}
123
456
789
789
456
1000
2000
リスト : メソッド呼び出しの型強制

use std::ops::Deref;

struct Foo {
    num: i32
}

impl Foo {
    fn foo(&self) {
        println!("{}", self.num)
    }
}

struct Bar {
    content: Foo
}

impl Deref for Bar {
    type Target = Foo;
    fn deref(&self) -> &Foo {
        &self.content
    }
}

fn main() {
    let a = Box::new(Foo { num: 123 });
    let b = Bar { content: Foo { num: 456 } };
    let c = Box::new(Bar { content: Foo { num: 789 } });
    a.foo();
    b.foo();
    c.foo();
}
123
456
789

●Rc<T>

リスト : Rc<T> の簡単な使用例 (1)

use std::rc::Rc;

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

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

fn main() {
    let a = Rc::new(Foo { num: 123 });
    println!("{}", Rc::strong_count(&a));
    let x = Box::new(Foo { num: 456 });
    println!("{}", x.num);
    {
        let b = a.clone();
        println!("{}", Rc::strong_count(&a));
        println!("{}", Rc::strong_count(&b));
        let c = &a;
        println!("{}", Rc::strong_count(&a));
        println!("{}", Rc::strong_count(c));
        let y = x.clone();
        println!("{}", y.num);
    }
    println!("{}", Rc::strong_count(&a));
}
1
456
2
2
2
2
456
Drop foo 456
1
Drop foo 456
Drop foo 123
リスト : Rc<T> の簡単な使用例 (2)

use std::rc::Rc;

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

fn main() {
    let a = Box::new(Foo { num: 123 });
    let b = *a;   // move
    // println!("{}", a.num); コンパイルエラー
    println!("{}", b.num);

    let c = Rc::new(Foo { num: 456 });
    // let x = *c;    Rc の場合は単純に move することはできない
    {
        let d = c.clone();
        // 参照カウンタが 1 よりも多いと Err
        match Rc::try_unwrap(d) {
            Ok(x) => println!("{}", x.num),
            Err(x) => println!("error {:?}", x)
        }
    }
    // 参照カウンタが 1 ならば Ok
    match Rc::try_unwrap(c) {
        Ok(x) => println!("{}", x.num),
        Err(x) => println!("error {:?}", x)
    }
}
123
error Foo { num: 456 }
456
リスト : 簡単な連結リスト (Rc 版)

use std::rc::Rc;

#[derive(Debug)]
enum List {
    Nil,
    Cons(i32, Rc<List>)
}

use List::*;

impl List {
    fn new() -> Rc<List> {
        Rc::new(Nil)
    }
    fn cons(x: i32, xs: &Rc<List>) -> Rc<List> {
        Rc::new(Cons(x, xs.clone()))
    }
}

impl Drop for List {
    fn drop(&mut self) {
        match *self {
            Nil => println!("drop Nil"),
            Cons(x, _) => println!("drop {}", x)
        }
    }
}

fn main() {
    let a = List::new();
    println!("{:?}", a);
    {
        let b = List::cons(1, &a);
        println!("{:?}", a);
        println!("{:?}", b);
        println!("{}", Rc::strong_count(&a));
        println!("{}", Rc::strong_count(&b));
        {
            let c = List::cons(2, &b);
            println!("{:?}", a);
            println!("{:?}", b);
            println!("{:?}", c);
            println!("{}", Rc::strong_count(&a));
            println!("{}", Rc::strong_count(&b));
            println!("{}", Rc::strong_count(&c));
        }
        println!("{}", Rc::strong_count(&a));
        println!("{}", Rc::strong_count(&b));
    }
    println!("{}", Rc::strong_count(&a));
}
Nil
Nil
Cons(1, Nil)
2
1
Nil
Cons(1, Nil)
Cons(2, Cons(1, Nil))
2
2
1
drop 2
2
1
drop 1
1
drop Nil

●Cell<T> と RefCell<T>

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

use std::cell::Cell;

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

fn main() {
    let a = Cell::new(123);
    println!("{:?}", a);
    println!("{}", a.get());
    a.set(456);
    println!("{:?}", a);
    println!("{}", a.get());

    let b = Foo { x: 789, y: Cell::new(999) };
    println!("{:?}", b);
    b.y.set(1000);
    println!("{:?}", b);

    let c = Box::new(Cell::new(1.234));
    println!("{}", c.get());
    c.set(5.678);
    println!("{}", c.get());
}
Cell { value: 123 }
123
Cell { value: 456 }
456
Foo { x: 789, y: Cell { value: 999 } }
Foo { x: 789, y: Cell { value: 1000 } }
1.234
5.678
リスト : RefCell の簡単な使用例

use std::cell::RefCell;

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

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

#[derive(Debug)]
struct Bar {
    foo: RefCell<Foo>
}

fn main() {
    let a = RefCell::new(123);
    println!("{:?}", a);
    {
        println!("{}", *a.borrow());  // immutable な参照
    }
    {
        let mut ref_a = a.borrow_mut();   // mutable な参照
        *ref_a = 456;
        // println!("{}", *a.borrow());  immutable な参照を借りるとパニック
    }
    println!("{}", *a.borrow());  //immutable な参照
    
    let b = Bar { foo: RefCell::new(Foo { x: 123 })};
    println!("{:?}", b);
    {
        println!("{:?}", *b.foo.borrow());  // immutable な参照
    }
    {
        let mut ref_b = b.foo.borrow_mut();   // mutable な参照
        *ref_b = Foo { x: 456 };              // Foo { x: 123 } は廃棄される
    }
    println!("{:?}", b);

    let c = Box::new(RefCell::new(Foo { x: 789 }));
    println!("{:?}", c);
    {
        println!("{}", c.borrow().x);     // フィールド x の値を参照する
        c.borrow_mut().x = 999;           // フィールド x の値を書き換える
        println!("{:?}", c);
    }
    {
        let mut ref_c = c.borrow_mut();   // mutable な参照
        *ref_c = Foo { x: 1000 };         // Foo { x: 999 } は廃棄される
    }

    let d = c.into_inner();    // メソッド into_inner() は中身のデータを move する
    // println!("{:?}", c);    コンパイルエラーになる
    println!("{:?}", d);
}
RefCell { value: 123 }
123
456
Bar { foo: RefCell { value: Foo { x: 123 } } }
Foo { x: 123 }
drop foo 123
Bar { foo: RefCell { value: Foo { x: 456 } } }
RefCell { value: Foo { x: 789 } }
789
RefCell { value: Foo { x: 999 } }
drop foo 999
Foo { x: 1000 }
drop foo 1000
drop foo 456
リスト : Cell の簡単な使用例 (その2)

use std::cell::Cell;

struct Foo {
    num: Cell<i32>
}

impl Foo {
    fn new(x: i32) -> Foo {
        Foo { num: Cell::new(x) }
    }
    fn get_num(&self) -> i32 {
        self.num.get()
    }
    fn set_num(&self, x: i32) {   // immutable な参照でも更新できる
        self.num.set(x)
    }
}

fn main() {
    let a = Foo::new(100);
    let b = &a;
    let c = &a;
    println!("{}", a.get_num());
    println!("{}", b.get_num());
    println!("{}", c.get_num());
    c.set_num(200);
    println!("{}", a.get_num());
    println!("{}", b.get_num());
    println!("{}", c.get_num());
}
100
100
100
200
200
200

●format! と Display

リスト : write! の簡単な使用例

use std::io::{self, Write};

fn main () {
    let mut buff = Vec::new();
    write!(&mut buff, "hello, world").unwrap();
    write!(&mut buff, "{}, {}, {}", 1, 1.2345, "foo bar baz").unwrap();
    io::stdout().write(&buff).unwrap();
}
hello, world1, 1.2345, foo bar baz
リスト : Display トレイトの簡単な実装例

use std::fmt;

struct Point {
    x: i32, y: i32
}

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    let a = Point { x: 0, y: 0 };
    let b = Point { x: 10, y: 20 };
    println!("{}, {}", a, b);
}
(0, 0), (10, 20)

●VecDeque<T>

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

use std::collections::VecDeque;

fn main() {
    // スタック (Stack) の動作
    let mut s = VecDeque::new();
    for x in 0 .. 10 {
        s.push_back(x);
    }
    println!("{:?}", s);
    while !s.is_empty() {
        println!("{}", s.pop_back().unwrap());
    }
    // キュー (Queue) の動作
    let mut q = VecDeque::new();
    for x in 10 .. 20 {
        q.push_back(x);
    }
    println!("{:?}", q);
    while !q.is_empty() {
        println!("{}", q.pop_front().unwrap());
    }
}
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
9
8
7
6
5
4
3
2
1
0
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
10
11
12
13
14
15
16
17
18
19

●LinkedList<T>

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

use std::collections::LinkedList;

fn main() {
    // スタック (Stack) の動作
    let mut s = LinkedList::new();
    for x in 0 .. 10 {
        s.push_back(x);
    }
    println!("{:?}", s);
    while !s.is_empty() {
        println!("{}", s.pop_back().unwrap());
    }
    // キュー (Queue) の動作
    let mut q = LinkedList::new();
    for x in 10 .. 20 {
        q.push_back(x);
    }
    println!("{:?}", q);
    while !q.is_empty() {
        println!("{}", q.pop_front().unwrap());
    }
}

結果は VecDeque の簡単な使用例と同じ。

●HashMap<K, V> と HashSet<T>

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

use std::collections::HashMap;

fn main() {
    let mut ht = HashMap::new();
    ht.insert("foo", 1);
    ht.insert("bar", 2);
    ht.insert("baz", 3);
    ht.insert("oops", 4);
    println!("{:?}", ht);
    println!("{}", ht.contains_key("baz"));
    println!("{}", ht.contains_key("Baz"));
    println!("{:?}", ht.get("foo"));
    println!("{:?}", ht.get("Foo"));
    println!("{:?}", ht.remove("Oops"));
    println!("{:?}", ht.remove("oops"));
    println!("{:?}", ht.insert("foo", 100));
    println!("{:?}", ht.insert("oops", 200));
    for (k, v) in ht.iter() {
        println!("{}, {}", k, v);
    }
}
{"baz": 3, "bar": 2, "foo": 1, "oops": 4}
true
false
Some(1)
None
None
Some(4)
Some(1)
None
baz, 3
bar, 2
foo, 100
oops, 200
リスト : HashSet の簡単な使用例

use std::collections::HashSet;

fn main() {
    let a: HashSet<_> = [1,2,3,4].iter().cloned().collect();
    let b: HashSet<_> = [3,4,5,6].iter().cloned().collect();
    println!("{:?}", a);
    println!("{:?}", b);
    println!("{}", a.contains(&1));
    println!("{}", b.contains(&1));
    let c: HashSet<_> = a.union(&b).cloned().collect();
    println!("{:?}", c);
    let d: HashSet<_> = a.intersection(&b).collect();
    println!("{:?}", d);
    let e: HashSet<_> = a.difference(&b).collect();
    println!("{:?}", e);
    println!("{}", a.is_subset(&c));
    println!("{}", b.is_subset(&c));
    println!("{}", a.is_subset(&b));
}
{4, 2, 3, 1}
{4, 5, 3, 6}
true
false
{5, 4, 2, 6, 1, 3}
{3, 4}
{2, 1}
true
true
false

●Option<T>

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

fn main() {
    let mut a: Option<i32> = Some(100);
    let mut b: Option<i32> = None;
    println!("{}", a.is_some());
    println!("{}", b.is_none());
    {
        let c = a.as_mut().unwrap();
        *c = 200;
    }
    {
        let d = a.as_ref().unwrap();
        println!("{}", d);
    }
    let e = a.take();
    println!("{:?}", a);
    println!("{:?}", e);
    let f = b.take();
    println!("{:?}", b);
    println!("{:?}", f);
    let g = e.map(|v| v * v);
    println!("{:?}", e);
    println!("{:?}", g);
}
true
true
200
None
Some(200)
None
None
Some(200)
Some(40000)

●AsRef と AsMut

リスト : 簡単な使用例

struct Foo<T> {
    item: T
}

impl<T> AsRef<T> for Foo<T> {
    fn as_ref(&self) -> &T {
        &self.item
    }
}

impl<T> AsMut<T> for Foo<T> {
    fn as_mut(&mut self) -> &mut T {
        &mut self.item
    }
}

fn get<T: AsRef<i32>>(n: &T) -> &i32 {
    n.as_ref()
}

fn inc<T: AsMut<i32>>(n: &mut T, m: i32) {
    *n.as_mut() += m;
}

fn main() {
    let mut a = Foo { item: 100 };
    println!("{}", get(&a));
    inc(&mut a, 100);
    println!("{}", get(&a));
}
100
200

●Borrow

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

use std::borrow::Borrow;
use std::collections::HashMap;

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

impl Borrow<i32> for Foo {
    fn borrow(&self) -> &i32 {
        &self.num
    }
}

fn main() {
    let mut ht: HashMap<Foo, i32> = HashMap::new();
    ht.insert(Foo { num: 1 }, 100);
    ht.insert(Foo { num: 2 }, 200);
    ht.insert(Foo { num: 3 }, 300);
    println!("{:?}", ht.get(&1));
    println!("{:?}", ht.get(&4));
    println!("{:?}", ht.get(&Foo { num: 2 }));
    println!("{:?}", ht.get(&Foo { num: 5 }));
}
Some(100)
None
Some(200)
None

●スレッド

リスト : スレッドの簡単な使用例 (1)

use std::{thread, time};

fn foo(msg: &str, n: u64) {
    let m = time::Duration::from_millis(n);
    for _ in 1 .. 10 {
        println!("{}", msg);
        thread::sleep(m);
    }
}

fn main() {
    let t1 = thread::spawn(|| {
        foo("oops", 500);
    });
    let t2 = thread::spawn(|| {
        foo("piyopiyo", 400);
    });
    println!("{:?}", t1.join().unwrap());
    println!("{:?}", t2.join().unwrap());
}
piyopiyo
oops
piyopiyo
oops
piyopiyo
oops
piyopiyo
oops
piyopiyo
piyopiyo
oops
piyopiyo
oops
piyopiyo
oops
piyopiyo
oops
oops
()
()
リスト : スレッドの簡単な使用例 (2)

use std::thread;
use std::time::Instant;

// フィボナッチ数列
fn fibo(n: i64) -> i64 {
    if n < 2 {
        n
    } else {
        fibo(n - 1) + fibo(n - 2)
    }
}

fn main() {
    let s1 = Instant::now();
    println!("{}", fibo(40));
    let e1 = s1.elapsed();
    println!("{}.{:03}秒経過しました。", e1.as_secs(), e1.subsec_nanos() / 1_000_000);

    let s2 = Instant::now();
    let mut buff: Vec<_> = vec![];
    buff.push(thread::spawn(|| fibo(40)));
    buff.push(thread::spawn(|| fibo(40)));
    for x in buff {
        println!("{}", x.join().unwrap());
    }
    let e2 = s2.elapsed();
    println!("{}.{:03}秒経過しました。", e2.as_secs(), e2.subsec_nanos() / 1_000_000);
}
102334155
0.771秒経過しました。
102334155
102334155
0.814秒経過しました。

●チャネル

リスト : チャネルの簡単な使用例

use std::thread;
use std::sync::mpsc;

fn fibo(n: i64) -> i64 {
    if n < 2 {
        n
    } else {
        fibo(n - 1) + fibo(n - 2)
    }
}

fn main() {
    let (tx, rx) = mpsc::channel();
    for x in vec![40, 39, 38, 37] {
        let tx = tx.clone();
        thread::spawn(move || tx.send(fibo(x)).unwrap());
    }
    for _ in 0 .. 4 {
        println!("{}", rx.recv().unwrap());
    }
}
24157817
39088169
63245986
102334155

●Arc と Mutex / RwLock

リスト : Arc と Mutex の簡単な使用例

use std::thread;
use std::sync::{Arc, Mutex};

fn main() {
    let data = Arc::new(vec![10, 20, 30, 40]);
    for i in 0 .. 4 {
        let data = data.clone();
        thread::spawn(move || {
            println!("{}", data[i]);
        }).join().unwrap();
    }
    let data1 = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
    for i in 0 .. 4 {
        let data1 = data1.clone();
        thread::spawn(move || {
            let mut buff = data1.lock().unwrap();
            buff[i] += 10;
            println!("{}", buff[i]);
        }).join().unwrap();
    }
    println!("{:?}", data1);
}
10
20
30
40
11
12
13
14
Mutex { data: [11, 12, 13, 14] }
リスト : RwLock の簡単な使用例 (1)

use std::sync::RwLock;

fn main() {
    let lock = RwLock::new(123);
    {
        let r1 = lock.read().unwrap();
        let r2 = lock.read().unwrap();
        println!("{}, {}", *r1, *r2);
        //let mut w1 = lock.write().unwrap();   ブロックされる
        //*w1 = 456;
        //println!("{}", *w1);
    }
    {
        let mut w1 = lock.write().unwrap();
        *w1 = 456;
        println!("{}", *w1);
        //let mut w2 = lock.write().unwrap();   ブロックされる
        //*w2 = 789;
        //println!("{}", *w2);
        //let r3 = lock.read().unwrap();       ブロックされる
        //println!("{}", *r3);
    }
}
123, 123
456
リスト : RwLock の簡単な使用例 (2)

use std::{thread, time};
use std::sync::{Arc, RwLock};

fn main() {
    let lock = Arc::new(RwLock::new(1));
    let t1;
    let t2;
    {
        let lock = lock.clone();
        t1 = thread::spawn(move || {
            for _ in 0 .. 10 {
                match lock.try_read() {
                    Ok(r) => println!("read data {}", *r),
                    _ => println!("Can't read data")
                }
                thread::sleep(time::Duration::from_millis(500));
            }
        });
    }
    {
        let lock = lock.clone();
        t2 = thread::spawn(move || {
            for _ in 0 .. 10 {
                match lock.try_write() {
                    Ok(mut w) => {
                        *w+= 1;
                        println!("write data {}", *w);
                    }
                    _ => println!("Can't write data")
                }
                thread::sleep(time::Duration::from_millis(500));
            }
        });
    }
    t1.join().unwrap();
    t2.join().unwrap();
}
read data 1
Can't write data
Can't read data
write data 2
write data 3
Can't read data
write data 4
read data 4
write data 5
read data 5
write data 6
read data 6
write data 7
read data 7
write data 8
read data 8
write data 9
read data 9
Can't read data
write data 10

Copyright (C) 2017 Makoto Hiroi
All rights reserved.

[ Home | Linux | Rust ]