Rust 演算子

二項演算子は、演算子の左右の値に作用する
let c = a + b;
+, -, *, /, %, &, |, ^, <<, >>

fn main(){
	let a = 0b010010;
	let b = 0b000111;

	println!("{:08b}", a & b);
	println!("{:08b}", a | b);
	println!("{:08b}", a ^ b);
}

ビットのシフトは、各ビットを左または右にシフトする
右にシフトすると値が小さくなり、左にシフトすると値が大きくなる

fn main(){
	let n = 1;
	println!("{}", n << 1);
	println!("{}", n << 2);
	println!("{}", n << 3);

	let m = 300;
	println!("{}", m >> 1);
	println!("{}", m >> 2);
	println!("{}", m >> 3);
}

単項演算子は右側の値が左側の値に作用する
比較演算子は左右の値の比較
論理演算子は左右の値または右側の値に作業して論理値を返す
代入演算子は右の値を左の変数に代入する

参照と参照外し
&は変数の参照を表す。参照の値に「*」を付けると値そのものを指す

fn main(){
	let x:i32 = 456;
	let r = &x;

	println!("x={}, r={}, *r={:?}", x, r, *r);
}

値の型の出力にはtype_of()を使う

fn main(){
	let x:i32 = 456;
	let r = &x;

	println!("x={}, type={:?}", x, type_of(x));
	println!("r={}, type={:?}", r, type_of(r));
	println!("*r={}, type={:?}", *r, type_of(*r));
}

fn type_of<T>(_: T) -> &'static str {
	std::any::type_name::<T>()
}
fn main(){
	let x:i32 = 456;
	let ref r = x;

	println!("x={}, r={}, *r={:?}", x, r, *r);
}
fn main(){
	let mut x:i32 = 456;
	let y = &mut x;
	*y = 123;

	println!("y={}", y);
	println!("y={} x={}", y, x);
}

Rustのその他の演算子
!, &, *, +, ,, -, -=, ->, ., .., ..=, …, /, /=, :, ;, =, =>, @, |, ?

演算子の結合順序
* / % << >> &
+ – | ^
== != < <= >= >=
&&
||

Rust 型の変換

fn main(){
	let n: i32 = 12;
	let v: f32 = n as f32;
	println!("{}->{}", n, v);
}
fn main(){
	let v = 123.45;
	let n = v as i32;
	println!("{}->{}", v, n);
}
let v = 12.56_f64;

let n = v.floor() as i32;
let m = v.ceil() as i32;
let l = v.round() as i32;

整数型から別の整数型への変換

fn main(){
	let n: i32 = 12;
	let v: i64 = n as i64;
	println!("{}->{}", n, v);
}
fn main(){
	let n: i64 = i64::MAX;
	let v: i32 = n as i32;
	println!("{}->{}", n, v);
}

実数型から別の実数型に変換するときもasを使う。この時に誤差が発生する場合がある

fn main(){
	let x: f32 = 7.6;
	let y: f64 = x as f64;
	println!("{}->{}", x, y);
}

7.6->7.599999904632568

文字列から数値へ変換するにはparse().unwrap()を使用する

fn main(){
	let s = "123";
	let v: u32 = s.parse().unwrap();
	println!("{}->{}", s, v);
}

あるいは parse::().unwrap()を使用する

fn main(){
	let s: &str = "123";
	let n: i32 = s.parse::<i32>().unwrap();

	println!("{:?}->{}", s, n);
}

文字列からバイト値に変換するにはas_bytes()を使用する

fn main(){
	let s: &str = "0";
	let n: &[u8] = s.as_bytes();

	println!("{}->{:?}", s, n);
}

数値から文字列への変換は to_string() を使用する

fn main(){
	let n: i32 = 123;
	let s = n.to_string();

	println!("{}->{}", n, s);
}

バイト値から文字列へ変換するにはstd::str::from_utf8().unwrap()を使用する

fn main(){
	let n: &[u8] = &[0x33];
	let s: &str = std::str::from_utf8(n).unwrap();

	println!("{:?}->{}", n, s);
}

Rust 文字リテラル

文字列リテラルは”~”で囲む
r”~”で囲んだ文字列をRaw文字列リテラルという
let msg:&str = r”Hello Dogs”;
b”~”で囲んだ文字列も[u8]のバイト列
let msg = b”Hello”;

fn main(){
	let msg:&str = r"Hello¥nDogs";

	println!("msg={}", msg);
}

エスケープシーケンス
¥b バックスペース
¥f フォームフィード
¥n 改行(line feed, newline)
¥r キャリッジリターン
¥t 水平タブ
¥v 垂直タブ
¥¥ バックスラッシュ
¥’ 単一引用符’
¥” 二重引用符”
¥xhh 2つの16進数
¥uhhhh 4つの16進数
¥Uhhhhhhhh 8つの16進数
¥ooo

水平タブ

fn main(){
	println!("12\tdef");
	println!("256\tmemory");
	println!("1024\tkiro");
}

### タプルと配列
タプルは複数の異なる型の値を1つのグループにすることができる複合型
配列は同じ型の要素を並べたもの

type: キーワードのtypeを使って型の別名(エイリアス)を定義することができる 別名の先頭は大文字にする。例えばu64にPopという別名を付けることができる

fn main(){
	type Pop = u64;
	let jp_pop: Pop = 123_456_789;
	let es_pop: Pop = 46_723_749;

	let total = jp_pop + es_pop + 456789_u64;

	println!("total={}", total);
}

### 変数と定数
不変の変数: let x = 10;
コンパイラが推測して決定することは型推論という
let zero: i64 = 0;
可変の変数を宣言するときはlet mutを使用する

fn main(){
	let mut x = 123;
	println!("x={}", x);

	x = 64;
	println!("x={}", x);
}
fn main(){
	let mut x = 123;
	println!("x={}", x);

	x = 23;
	println!("x={}", x);

	let x = "こんにちは";
	println!("x={}", x);
}

定数とはプログラムの実行中に内容が変わらない値に名前を付けたもの
const MAX_DATA: u32 = 100;
const HELL:&str = “Hello, Dogs”;

Rustには所有権という概念がある。これは変数は値を所有するという概念

fn main(){
	let s1 = String::from("hello Rust");
	let s2 = s1.clone();

	println!("s1={}, s2={}", s1, s2);
}

有効範囲
関数の中で宣言した定数や{~}の中で宣言した定数はその中で有効

fn main(){
	let x = 3;
	{
		let x = 12;
		println!("x={}", x);
	}
	let y = x * 2;

	println!("x={}", x);
	println!("y={}", y);
}

static変数は、モジュールのどこからでも参照できる変数
static mul VAL: i32 = 123;

static mut VAL: i32 = 123;

fn main(){
	unsafe {
		println!("VAL={}", VAL);
	}

	twice();

	unsafe {
		println!("VAL={}", VAL);
	}
}

fn twice(){
	unsafe {
		VAL = VAL * 2;
		println!("VAL in twice()={}", VAL);
	}
}

Rustのデータ型1

Rustのデータ型は整数(integer)、浮動小数点(floating-point number)、ブール値(Boolean)、キャラクタ(character)という4種類のスカラー型(scalar type)と、タプル(tuple)と配列(array)という2種類の複合型(Compound Type)などがある

### Rustのプリミティブ型
bool, char, f32(32ビット浮動小数点型), f64(64ビット浮動小数点型), fn(関数ポインタ), i8(8ビット符号付き整数), i16(16ビット符号付き整数), i32(32ビット符号付き整数),  i64(64ビット符号付き整数),  i128(128ビット符号付き整数), isize(ポインタのサイズの符号付き整数), str(文字列スライス型), tuple, u8(8ビット符号なし整数), u16(16ビット符号なし整数), u32(32ビット符号なし整数), u64(64ビット符号なし整数), u128(128ビット符号なし整数), usize(ポインタのサイズの符号なし整数), *const(ポインタ型(unsafe*)), *mut(ポインタ型(unsafe*)), &(参照型), スライス(スライス型), ()(unit型), !(never型), [](配列)

u8: 0~255
u16: 0~65535
u32: 0~4294967295
u64: 0~18446744073709551615
u128

i8: -128~127
i16: -32768~32767
i32: -2147483648 ~ -2147483647
i64: -9223372036854775808 ~ 9223372036854775807
i128
unsize, isize

整数
let x = 18;
桁の大きい10進数整数
const MAX_POINTS: u32 = 100_000;
16進数
let x = 0x12;
8進数
let x = 0o22;
2進数
let x = 0b010010;
桁の大きい2進数
let x = 0b01_0010;
let u b’A’; let a = b’;’; let a = b’あ’;
リテラルの型を明示
let n = 3_i16;

浮動小数点
f32: 32ビット浮動小数点数
f64: 64ビット浮動小数点数

fn main(){
	let x = 7.0;
	println!("{}", type_of(x));
}

fn type_of<T>(_: T) -> &'static str {
	std::any::type_name::<T>()
}

型を指定するときはf32, f64を使う

fn main(){
	let x: f32 = 7.0;
	let y: f64 = 0.3;

	println("x*y={}", x as f64 * y);
}
fn main(){
	let x: f32 = 7.0;
	let y = 3.2;

	println!("{} {} {}", x, y, x + y);
}

Rustの基本的な要素

名前: 半角英字

fn main(){
	let age = 10;
	println!("age={}", age);
}
fn main(){
	let dog1_age = 10;
	println!("dog1_age={}", dog1_age);
}

先頭に「_」を付けたり、「_」だけの名前は使わない変数を表す

fn main(){
	let mut _a = 9;
	let _ = 12;

	println!("表示する値がありません");
}

式は let x = 5; などと表す
関数の場合は printdata(a, b); など。何もしない時は()を使うことがよくある

Rustのプロジェクトとビルド

大規模なプログラムを作成する場合は関連ファイルをプロジェクトと呼ぶ単位で扱うと便利なことがある
プロジェクトを作成するには、作成したいフォルダでcargo newを実行する

$ cargo new helloprj —bin
Created binary (application) `helloprj` package
$ cd helloprj
$ tree
.
├── Cargo.toml
└── src
└── main.rs

main.rs

fn main() {
    println!("Hello, world!");
}

$ cargo build

buildして実行する場合
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/helloprj`
Hello, world!

Rust playground
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021

Rustを始める

従来のプログラミング言語の優れた点を採用し、問題点を排除して作成された

// dispfile.rs
use std::env;
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
	let argv: Vec<String> = env::args().collect(); // コマンドライン引数
	if argv.len() < 2 {
		println!("引数にファイル名を指定してください。");
		std::process:exit(1);
	}

	let f = File::open(&argv[1])?;
	let reader = BufReader::new(f);

	for line in reader.lines() {
		println!("{}", line?);
	}
	Ok(())
}

[Rust] Basic 1: variable and array

### variables

fn main() {
    let x = 13;
    println!("{}", x);

    let x: f64 = 3.14159;
    println!("{}", x);

    let x;
    x = 0;
    println!("{}", x);
}

$ target/debug/hello
13
3.14159
0

variables are modifiable.
mutable: compiler allows read and write
immutable: the compiler will only allow the variable to be read from
mutable values are denoted with a mut keyword.

fn main() {
    let mut x = 42;
    println!("{}", x);
    x = 13;
    println!("{}", x);
}

booleans: bool
unsigned integers(符号なし): u8, u16, u32, u64, u128
signed integers(符号あり): i8, i16, i32, i64, i128
pointer sized integers: usize, isize
floating point: f32, f64
tuple: (value, value, …)
arrays:
slices,
str
Numeric types can be explicitly specified by appending the type to the end of the number.(13u32, 2u8)

fn main() {
    let x = 12;
    let a = 12u8;
    let b = 4.3;
    let c = 4.3f32;
    let bv = true;
    let t = (13, false);
    let sentence = "hello world";
    println!(
    	"{} {} {} {} {} {} {} {}",
    	x, a, b, c, bv, t.0, t.1, sentence
    )
}

$ target/debug/hello
12 12 4.3 4.3 true 13 false hello world

### Basic Type Conversion
as で変換する

fn main() {
    let a = 13u8;
    let b = 7u32;
    let c = a as u32 + b;
    println!("{}", c);

    let t = true;
    println!("{}", t as u8);
}

$ target/debug/hello
20
1

### constants
constant used many times efficiently.
constant must always have explicit types.
constant names are always in SCREAMING_SNAKE_CASE.

const PI: f32 = 3.14159;

fn main() {
    println!(
    	"to make an apple {} from scratch, you must first create a universe.",
    	PI
    )
}

const PI: u8 = 12; とも書く

### Arrays
an array is a fixed length collection of data.
data type for an array is [T;N] where T is the elements type and N is the fixed length.
Individual elements can be retrieved with the x operator

fn main() {
    let nums: [i32; 3] = [1, 2, 3];
    println!("{:?}", nums);
    println!("{}", nums[1]);
}

$ target/debug/hello
[1, 2, 3]
2

なるほど

Ubuntu20.04 でRustの環境構築

$ curl –proto ‘=https’ –tlsv1.2 -sSf https://sh.rustup.rs | sh
$ sudo apt install cargo
$ cargo new –bin hello
$ cd hello
$ cargo build
Compiling hello v0.1.0 (/home/vagrant/dev/rust/hello)
Finished dev [unoptimized + debuginfo] target(s) in 0.32s
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
├── CACHEDIR.TAG
└── debug
├── build
├── deps
│   ├── hello-2ab4b0e0c3958f3e
│   └── hello-2ab4b0e0c3958f3e.d
├── examples
├── hello
├── hello.d
└── incremental

7 directories, 8 files

$ target/debug/hello
Hello, world!

ファイルの中身を見てみる
hello/src/main.rs

fn main() {
    println!("Hello, world!");
}

中身をtour of rustと同じにする

fn main() {
    println!("Hello, 🦀");
}

$ cargo build
$ target/debug/hello
Hello, 🦀

なるほど…