【Rust】構造体のライフタイム注釈

#[derive(Debug)]
struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
    println!("{:?}", i);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.26s
Running `target/debug/stackmachine`
ImportantExcerpt { part: “Call me Ishmael” }

なるほど、参照時にライフタイムを指定するのか、、面白いですね。

【Rust】ライフタイムとは

ライフタイムとは、参照が有効になるスコープのこと。
型推論と同じように、ライフタイムがいくつか異なる方法で関係ある場合は注釈を入れなければならない

fn main() {
    let r;

    {
        let x = 5;
        r = &x;
    }

    println!("r: {r:?}");
}

Compiling stackmachine v0.1.0 (/home/vagrant/dev/rust/stackmachine)
error[E0597]: `x` does not live long enough
xはrよりもスコープが短いのでエラーになる

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);

    println!("The longest string is {result:?}");
}

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

error[E0106]: missing lifetime specifier
–> src/main.rs:10:33
|
10 | fn longest(x: &str, y: &str) -> &str {
| —- —- ^ expected named lifetime parameter

ジェネリックなライフタイム引数を指定された関数は、あらゆるライフタイムの参照を受け取ることができる。

&i32
&’a i32 // 明示的なライフタイム参照
&’a mut i32 // 明示的なライフタイム参照

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

同じだけライフライむを生きると伝えている

fn main() {
    let string1 = String::from("long string is long");
    let result;
    {
        let string2 = String::from("xyz");
        result = longest(string1.as_str(), string2.as_str());
    }
    println!("The longest string is {result:?}");
    
}

error[E0597]: `string2` does not live long enough
–> src/main.rs:6:44
|
5 | let string2 = String::from(“xyz”);
| ——- binding `string2` declared here
6 | result = longest(string1.as_str(), string2.as_str());
| ^^^^^^^ borrowed value does not live long enough
7 | }
| – `string2` dropped here while still borrowed
8 | println!(“The longest string is {result:?}”);
| ———- borrow later used here

【Rust】スタックベース仮想マシンの基礎

fn main() {
    let mut stack = vec![];

    stack.push(42);
    stack.push(36);

    add(&mut stack);

    println!("stack: {stack:?}");
}

fn add(stack: &mut Vec<i32>){
    let lhs = stack.pop().unwrap();
    let rhs = stack.pop().unwrap();
    stack.push(lhs + rhs);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
Running `target/debug/stackmachine`
stack: [78]

### 標準入力からの読み込み

fn main() {
    for line in std::io::stdin().lines() {
        if let Ok(line) = line {
            let words: Vec<_> = line.split(" ").collect();
            println!("Line: {words:?}");
        }
    }
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.82s
Running `target/debug/stackmachine`
42 3 +
Line: [“42”, “3”, “+”]

### 文字列のパースと実行

fn main() {
    for line in std::io::stdin().lines() {
        let mut stack = vec![];
        if let Ok(line) = line {
            let words: Vec<_> = line.split(" ").collect();
            
            for word in words {
                if let Ok(parsed) = word.parse::<i32>() {
                    stack.push(parsed);
                } else {
                    match word {
                        "+" => add(&mut stack),
                        _ => panic!("{word:?} could not be parsed"),
                    }
                }
            }
            println!("stadk: {stack:?}");

        }
    }
}

fn add(stack: &mut Vec<i32>){
    let lhs = stack.pop().unwrap();
    let rhs = stack.pop().unwrap();
    stack.push(lhs + rhs);
}

### 四則演算

fn main() {
    for line in std::io::stdin().lines() {
        let mut stack = vec![];
        if let Ok(line) = line {
            let words: Vec<_> = line.split(" ").collect();
            
            for word in words {
                if let Ok(parsed) = word.parse::<i32>() {
                    stack.push(parsed);
                } else {
                    match word {
                        "+" => add(&mut stack),
                        "-" => sub(&mut stack),
                        "*" => mul(&mut stack),
                        "/" => div(&mut stack),
                        _ => panic!("{word:?} could not be parsed"),
                    }
                }
            }
            println!("stadk: {stack:?}");

        }
    }
}

fn add(stack: &mut Vec<i32>){
    let rhs = stack.pop().unwrap();
    let lhs = stack.pop().unwrap();
    stack.push(lhs + rhs);
}

fn sub(stack: &mut Vec<i32>){
    let rhs = stack.pop().unwrap();
    let lhs = stack.pop().unwrap();
    stack.push(lhs - rhs);
}

fn mul(stack: &mut Vec<i32>){
    let rhs = stack.pop().unwrap();
    let lhs = stack.pop().unwrap();
    stack.push(lhs * rhs);
}

fn div(stack: &mut Vec<i32>){
    let rhs = stack.pop().unwrap();
    let lhs = stack.pop().unwrap();
    stack.push(lhs / rhs);
}

【Rust】最大値・最小値【Algorithm】

変数を用意しておいて、最大値、最小値の値を更新していくだけですね。
ループを抜けるのは10000以上か0以下としています。

fn main() {

   let mut imax: i32 = -1;
   let mut imin: i32 = 10000;
   let mut kmax: i32 = 0;
   let mut kmin: i32 = 0;
   let mut k: i32 = 0;
   let mut i: i32 = 0;

   while(i >= 0 && i <= 9999){
      println!("4桁以内の正の整数を入力してください。");
      let mut x = String::new();
      std::io::stdin().read_line(&mut x).expect("Failed to read line");
      x = x.trim_end().to_owned();
      i = x.parse::<i32>().unwrap();
      if (0 < i && i < 10000) {
         k += 1;
         if(imax < i) {
            imax = i;
            kmax = k;
         }

         if(imin > i) {
            imin = i;
            kmin = k;
         }
      }
   }

   if (k == 0) {
      println!("入力されていません。");
   } else {
      println!("最大値 {}({}回目)", imax, kmax);
      println!("最小値 {}({}回目)", imin, kmin);
   }
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.90s
Running `target/debug/basic`
4桁以内の正の整数を入力してください。
100
4桁以内の正の整数を入力してください。
20
4桁以内の正の整数を入力してください。
50
4桁以内の正の整数を入力してください。
29
4桁以内の正の整数を入力してください。
829
4桁以内の正の整数を入力してください。
2222
4桁以内の正の整数を入力してください。
2452
4桁以内の正の整数を入力してください。
11245
最大値 2452(7回目)
最小値 20(2回目)

うーむ なるほど〜

【Rust】反復処理【Algorithm】

偶数の和の場合は、n += 2;とする

fn main() {

   let mut n: i32 = 1;
   let mut t: i32 = 0;

   while n <= 100 {
      t = t + n;
      n += 1;
   }
   println!("{}", t);
}
fn main() {

   println!("入力されたmからnまでの合計を求めます。二つの数字を入力してください。");
   let mut x = String::new();
   let mut y = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   let mut x: i32 = x.parse::<i32>().unwrap();
   std::io::stdin().read_line(&mut y).expect("Failed to read line");
   y = y.trim_end().to_owned();
   let mut y: i32 = y.parse::<i32>().unwrap();
   
   if x > y {
      println!("mの方が大きいです。")
   }
   let mut w: i32 = 0;
   while x <= y {
      w = w + x;
      x += 1;
   }
   println!("mからnまでの合計値は{}", w);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.38s
Running `target/debug/basic`
入力されたmからnまでの合計を求めます。二つの数字を入力してください。
2
5
mからnまでの合計値は14

ユークリッド互助法

fn main() {

   println!("最大公約数を求めます。二つの数字を入力してください。");
   let mut x = String::new();
   let mut y = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   let mut x: i32 = x.parse::<i32>().unwrap();
   std::io::stdin().read_line(&mut y).expect("Failed to read line");
   y = y.trim_end().to_owned();
   let mut y: i32 = y.parse::<i32>().unwrap();
   
   let mut a: i32;
   let mut b: i32;
   let mut r: i32;
   if (x > y) {
      a = x;
      b = y;
   } else {
      a = y;
      b = x;
   }

   r = a % b;

   while (r != 0) {
      a = b;
      b = r;
      r = a % b;
   }
   println!("最大公約数は{}", b);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
Running `target/debug/basic`
最大公約数を求めます。二つの数字を入力してください。
100
75
最大公約数は25

【Rust】分岐処理【Algorithm】

fn main() {

   println!("数字を入力してください。");
   let mut x = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   let x: i32 = x.parse::<i32>().unwrap();

   if x > 100 {
      println!("{}は100より大きい", x);
   } else {
      println!("{}は100より小さい", x);
   }
}

最小値

fn main() {

   let a = 10;
   let b = 15;
   let c = 9;
   let mut w: i32;

   if a <= b {
      if a <= c {
         w = a;
      } else {
         w = c;
      }
   } else {
      if b <= c {
         w = b;
      } else {
         w = c;
      }
   }
   println!("{}", w);
}

Rustにはstd::cmp::minという関数があるが、argmentは2つでないといけない
https://doc.rust-lang.org/std/cmp/fn.min.html
std::cmp::min(a, b, c);とは書けない。

fn main() {

   let a = 10;
   let b = 15;
   let c = 9;
   let mut w: i32;
   
   if(a <= b && a <= c) {
      w = a;
   } else if (a <= b && a > c) {
      w = c;
   } else if (a > b && b <= c) {
      w = b;
   } else {
      w = c;
   }
   println!("{}", w);
}

計算量を少なくする方法

fn main() {

   let a = 10;
   let b = 15;
   let c = 9;
   let mut w: i32;
   
   w = a;
   if(b < w) {
      w = b;
   }
   if (c < w) {
      w = c;
   }
   println!("{}", w);
}

大文字小文字

fn main() {

   println!("一文字入力してください。");
   let mut x = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   let char_vec: Vec<char> = x.chars().collect();
   for y in char_vec {
      if y.is_uppercase() {
         println!("大文字です");
      } else {
         println!("子文字です");
      }
   }
}

【Rust】四則演算【Algorithm】

fn main() {

   println!("二つの数字を入力してください。");
   let mut x = String::new();
   let mut y = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   let x: i32 = x.parse::<i32>().unwrap();
   std::io::stdin().read_line(&mut y).expect("Failed to read line");
   y = y.trim_end().to_owned();
   let y: i32 = y.parse::<i32>().unwrap();

   println!("{} + {} = {}", x, y, x+y);
   println!("{} - {} = {}", x, y, x-y);
   println!("{} * {} = {}", x, y, x*y);
   println!("{} / {} = {}", x, y, x/y);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/basic`
二つの数字を入力してください。
24
6
24 + 6 = 30
24 – 6 = 18
24 * 6 = 144
24 / 6 = 4

【Rust】mem::swap【Algorithm】

mem::swap(&mut x, &mut y);でswapできる。
https://doc.rust-lang.org/std/mem/fn.swap.html

use std::mem;

fn main() {

   println!("二つの数字を入力してください。");
   let mut x = String::new();
   let mut y = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   std::io::stdin().read_line(&mut y).expect("Failed to read line");
   y = y.trim_end().to_owned();

   mem::swap(&mut x, &mut y);
   println!("入力した値をswapすると「{}」と「{}」です", x, y);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/basic`
二つの数字を入力してください。
20
15
入力した値をswapすると「15」と「20」です

既に用意されているのね…

【Rust/React.js】jsonで保存したデータをsetTimeoutで表示する

React(Json)で、入れ子のデータを扱うには、data.map((value) => と書くと、for(let d in data) のような処理ができる。

main.rs

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Name {
    first : String,
    last: String,
}

#[tokio::main]
async fn main()  {
    let mut names : Vec<Name> = Vec::new();
    let n1 = Name { first:"taro".to_string(), last:"yamata".to_string()};
    let n2 = Name { first:"hajime".to_string(), last:"tanaka".to_string()};
    let n3 = Name { first:"hanako".to_string(), last:"yoshida".to_string()};
    names.push(n1);
    names.push(n2);
    names.push(n3);
    println!("{:?}", names);
    let serialized: Vec<u8> = serde_json::to_vec(&names).unwrap();
    println!("{:?}", serialized);
    let file_path = format!("./data/data.txt");
    let mut file = File::create(file_path.clone()).unwrap();
    file.write_all(&serialized).expect("write failed");

}

data.txt

[{"first":"taro","last":"yamata"},{"first":"hajime","last":"tanaka"},{"first":"hanako","last":"yoshida"}]

App.js

import React, {Component} from 'react';
import './App.css';
 
class App extends Component {
 
  render() {
    return <div className="App">
    <h1>React</h1>
    <Blocks />
  </div>;
  }
}
 
class Blocks extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
    };
  }

  componentDidMount() {
      this.timer = setInterval(
          () => 
              fetch('./data/data.text').then(response => {
                  return response.json();
                  }).then(json => {
                      this.setState({ data: json});
                  }),
          2000,
      );
  }

  componentWillUnmount() {
      clearInterval(this.timer);
  }

  render() {
    if (this.state.data) {
      return <div>
        {this.state.data.map((value) => (
          <p>名前:{value.first} {value.last}</p>
        ))}
      </div>
    }
    else {
      return <div>Loading...</div>
    }
  }
}
export default App;

これを少し応用したい。

【Rust】ステートマシンによるメール判定【Algorithm】

fn isalphanum(c: char) -> bool {
    return c.is_alphabetic() || c.is_numeric();
}

fn isdot(c: char) -> bool {
    return c == '.';
}

fn isatmark(c: char) -> bool {
    return c == '@';
}

fn isend(c: char) -> bool {
    return c == '$';
}

fn isemail(mut s: String) -> bool {
    s += "$";

    let INIT = 0;
    let LOCAL_NOTDOT = 1;
    let LOCAL_DOT = 2;
    let ATMART = 3;
    let DOMAIN_NOTDOT = 4;
    let DOMAIN_DOT = 5;
    let OK = 6;
    let NG = 7;

    let mut state = INIT;

    for c in s.chars() {
        if state == INIT {
            if isalphanum(c) {
                state = LOCAL_NOTDOT;
            } else {
                state = NG;
                break;
            }
        } else if state == LOCAL_NOTDOT {
            if isalphanum(c) {
                state = LOCAL_NOTDOT;
            } else if isdot(c) {
                state = LOCAL_DOT;
            } else if isatmark(c) {
                state = ATMART;
            } else {
                state = NG;
                break;
            }
        } else if state == LOCAL_DOT {
            if isalphanum(c) {
                state = LOCAL_NOTDOT;
            } else {
                state = NG;
                break;
            }
        } else if state == ATMART {
            if isalphanum(c) {
                state = DOMAIN_NOTDOT;
            } else {
                state = NG;
                break;
            }
        } else if state == DOMAIN_NOTDOT {
            if isalphanum(c) {
                state = DOMAIN_NOTDOT;
            } else if isdot(c) {
                state = DOMAIN_DOT;
            } else if isend(c) {
                state = OK;
            } else {
                state = NG;
                break;
            }
        } else if state == DOMAIN_DOT {
            if isalphanum(c) {
                state = DOMAIN_NOTDOT;
            } else {
                state = NG;
                break;
            }
        } else if state == OK {
            break;
        } else if state == NG {
            break;
        } else {
            state = NG
        }
    }
    return state == OK;
}

fn main() {
    let email = "t@g.m".to_string();
    if isemail(email.clone()) {
        println!("メールアドレスです。{}", email);
    } else {
        println!("メールアドレスではありません。");
    }
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s
Running `target/debug/basic`
メールアドレスです。t@g.m