筆者が、Rust By Exampleを写経したり、Activityを実行したりした記録です
この記事のソースコード、記載は正しいかわかりませんし、効率的かどうかもわかりません
ご参考まで
Testcase: List
?
をつけて、write!マクロ出力を継続させるということか?
write!(f, "{}", value)?;
ソースコード
use std::fmt;
struct List(Vec<i32>);
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let vec = &self.0;
write!(f, "[")?;
for (count, v) in vec.iter().enumerate() {
if count != 0 { write!(f, ", ")?; }
write!(f, "{}:{}", v,count)?;
}
write!(f, "]")
}
}
fn main() {
let v = List(vec![1, 2, 3]);
println!("{}", v);
}
出力結果
[1:0, 2:1, 3:2]
Try
いちばん最初のwrite!
の?
を削除すると、エラーとなる
- write!(f, "[")?;
+ write!(f, "[");
最初のwrite!
で出力が終わってしまうことが原因かな?
Compiling testcase_list v0.1.0 (E:\github\rust_example\testcase_list)
warning: unused `Result` that must be used
--> src\main.rs:9:9
|
9 | write!(f, "[");
| ^^^^^^^^^^^^^^
|
= note: this `Result` may be an `Err` variant, which should be handled
= note: `#[warn(unused_must_use)]` on by default
= note: this warning originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
Formatting
各種Formattingの練習です
前述の?
も併用しました
右寄せとか0詰めとかも、まだ書き方に慣れていないため、これは繰り返し練習する
ソースコード
ソースコード
use std::fmt::{self, Formatter, Display};
#[derive(Debug)]
struct City {
name: &'static str,
lat: f32, // Latitude
lon: f32, // Longitude
}
impl Display for City {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };
let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };
write!(f, "{:>10}: {:.3}°{} {:.3}°{}",
self.name, self.lat.abs(), lat_c, self.lon.abs(), lon_c)
}
}
#[derive(Debug)]
struct Color {
red: u8,
green: u8,
blue: u8,
}
impl Display for Color {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "RGB({:>3}, {:>3}, {:>3}) ", self.red, self.green, self.blue)?;
write!(f, "0x")?;
write!(f, "{:02x}", self.red)?;
write!(f, "{:02x}", self.green)?;
write!(f, "{:02x}", self.blue)
}
}
fn main() {
let cities = [
City { name: "Dublin", lat: 53.347778, lon: -6.259722 },
City { name: "Oslo", lat: 59.95, lon: 10.75 },
City { name: "Vancouver", lat: 49.25, lon: -123.1 },
];
for city in &cities {
println!("{}", city);
}
for city in &cities {
println!("{:?}", city);
}
let colors = [
Color { red: 128, green: 255, blue: 90 },
Color { red: 0, green: 3, blue: 254 },
Color { red: 0, green: 0, blue: 0 },
];
for color in &colors {
println!("{}", color);
}
for color in &colors {
println!("{:?}", color);
}
}
出力結果
Dublin: 53.348°N 6.260°W
Oslo: 59.950°N 10.750°E
Vancouver: 49.250°N 123.100°W
City { name: "Dublin", lat: 53.34778, lon: -6.259722 }
City { name: "Oslo", lat: 59.95, lon: 10.75 }
City { name: "Vancouver", lat: 49.25, lon: -123.1 }
RGB(128, 255, 90) 0x80ff5a
RGB( 0, 3, 254) 0x0003fe
RGB( 0, 0, 0) 0x000000
Color { red: 128, green: 255, blue: 90 }
Color { red: 0, green: 3, blue: 254 }
Color { red: 0, green: 0, blue: 0 }
Premitives
primitives
: 基本データ型
type annotate
: 型指定
integersのデフォルト型はi32
、floatsはf64
ソースコード
ソースコード
fn main() {
let logical: bool = true;
println!("{}", logical);
let a_float: f64 = 1.0;
let an_integer = 5i32;
println!("{}", a_float);
println!("{}", an_integer);
let default_float = 3.0;
let default_integer = 7;
println!("{}", default_float);
println!("{}", default_integer);
let mut inferred_type = 12;
println!("{}", inferred_type);
inferred_type = 4294967296i64;
println!("{}", inferred_type);
let mut mutable = 12;
println!("{}", mutable);
mutable = 21;
println!("{}", mutable);
//mutable = true;
let mutable = true;
println!("{}", mutable);
}
出力結果
true
1
5
3
7
12
4294967296
12
21
true
Literals and operators
ソースコード
ソースコード
fn main() {
println!("1 + 2 = {}", 1u32 + 2);
//println!("1 - 2 = {}", 1u32 - 2);
println!("1 - 2 = {}", 1i32 - 2);
println!("1e4 is {}, -2.5e-3 is {}", 1e4, -2.5e-3);
// 論理演算
println!("true AND false is {}", true && false);
println!("true OR false is {}", true || false);
println!("NOT true is {}", !true);
// Bit演算
println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101);
println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101);
println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101);
println!("1 << 5 is {}", 1u32 << 5);
println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2);
println!("0b{:08b} >> 2 is 0b{:08b}", 0x80u32, 0x80u32 >> 2);
println!("One million is written as {}", 1_000_000u32);
}
出力結果
1 + 2 = 3
1 - 2 = -1
1e4 is 10000, -2.5e-3 is -0.0025
true AND false is false
true OR false is true
NOT true is false
0011 AND 0101 is 0001
0011 OR 0101 is 0111
0011 XOR 0101 is 0110
1 << 5 is 32
0x80 >> 2 is 0x20
0b10000000 >> 2 is 0b00100000
One million is written as 1000000
Try
overflowを起こす計算のうち、あらかじめ判明しているものはエラーとなる
- println!("1 - 2 = {}", 1i32 - 2);
+ println!("1 - 2 = {}", 1u32 - 2);
error: this arithmetic operation will overflow
--> src\main.rs:3:28
|
3 | println!("1 - 2 = {}", 1u32 - 2);
| ^^^^^^^^ attempt to compute `1_u32 - 2_u32`, which would overflow
|
= note: `#[deny(arithmetic_overflow)]` on by default
Tuples
12個より要素が多いタプルはデバッグプリントできない
要素が1個のタプルをつくれるが、,
が必要
ソースコード
ソースコード
use std::fmt;
fn reverse(pair: (i32, bool)) -> (bool, i32) {
let (int_parm, bool_parm) = pair;
(bool_parm, int_parm)
}
fn transpose(matrix: Matrix) -> Matrix {
Matrix(matrix.0, matrix.2, matrix.1, matrix.3)
}
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
impl fmt::Display for Matrix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "( {} {} )", self.0, self.1)?;
writeln!(f, "( {} {} )", self.2, self.3)
}
}
fn main() {
let long_tuple = (1u8, 2u16, 3u32, 4u64,
-1i8, -2i16, -3i32, -4i64,
0.1f32, 0.2f64,
'a', true);
println!("Long tuple first value: {}", long_tuple.0);
println!("Long tuple second value: {}", long_tuple.1);
let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);
println!("tuple of tuples: {:?}", tuple_of_tuples);
//let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
//println!("Too long tuple: {:?}", too_long_tuple);
let pair = (1, true);
println!("Pair is {:?}", pair);
println!("The reversed pair is {:?}", reverse(pair));
println!("One element tuple: {:?}", (5u32,));
println!("Just an integer: {:?}", (5u32));
let tuple = (1, "hello", 4.5, true);
let (a, b, c, d) = tuple;
println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);
let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
println!("{:?}", matrix);
println!("{}", matrix);
println!("Matrix:\n{}", matrix);
println!("Transpose:\n{}", transpose(matrix));
}
出力結果
Long tuple first value: 1
Long tuple second value: 2
tuple of tuples: ((1, 2, 2), (4, -1), -2)
Pair is (1, true)
The reversed pair is (true, 1)
One element tuple: (5,)
Just an integer: 5
1, "hello", 4.5, true
Matrix(1.1, 1.2, 2.1, 2.2)
( 1.1 1.2 )
( 2.1 2.2 )
Matrix:
( 1.1 1.2 )
( 2.1 2.2 )
Transpose:
( 1.1 2.1 )
( 1.2 2.2 )
Arrays and Slices
Arraysは同じ型のコレクションで、連続したメモリに配置される
arraysの長さはコンパイル時に既知、slicesの長さはコンパイル時に不定
ソースコード
ソースコード
use std::mem;
fn analyze_slice(slice: &[i32]) {
println!("First element of the slice: {}", slice[0]);
println!("The slice has {} elements", slice.len());
}
fn main() {
let xs: [i32; 5] = [1, 2, 3, 4, 5];
let ys: [i32; 500] = [0; 500];
println!("First element of the array: {}", xs[0]);
println!("Second element of the array: {}", xs[1]);
println!("Number of elements in array: {}", xs.len());
println!("Array occupies {} bytes", mem::size_of_val(&xs));
println!("Borrow the whole array as a slice.");
analyze_slice(&xs);
println!("Borrow a section of the array as a slice.");
analyze_slice(&ys[1..4]);
let empty_array: [u32; 0] = [];
assert_eq!(&empty_array, &[]);
assert_eq!(&empty_array, &[][..]);
for i in 0..xs.len() + 1 { // Oops, one element too far!
match xs.get(i) {
Some(xval) => println!("{}: {}", i, xval),
None => println!("Slow down! {} is too far!", i),
}
}
//println!("{}", xs[5]); // compile error
//println!("{}", xs[..][5]); // runtime error
}
出力結果
First element of the array: 1
Second element of the array: 2
Number of elements in array: 5
Array occupies 20 bytes
Borrow the whole array as a slice.
First element of the slice: 1
The slice has 5 elements
Borrow a section of the array as a slice.
First element of the slice: 0
The slice has 3 elements
0: 1
1: 2
2: 3
3: 4
4: 5
Slow down! 5 is too far!
Try
コンパイルエラーになる場合
println!("{}", xs[5]); // compile error
Compiling arrays_and_slices v0.1.0 (E:\github\rust_example\arrays_and_slices)
error: this operation will panic at runtime
--> src\main.rs:36:20
|
36 | println!("{}", xs[5]); // compile error
| ^^^^^ index out of bounds: the length is 5 but the index is 5
|
= note: `#[deny(unconditional_panic)]` on by default
error: could not compile `arrays_and_slices` (bin "arrays_and_slices") due to 1 previous error
ランタイムエラーになる場合
println!("{}", xs[..][5]); // runtime error
thread 'main' panicked at src\main.rs:37:20:
index out of bounds: the len is 5 but the index is 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\arrays_and_slices.exe` (exit code: 101)
Structures
3つのタイプのStructuresがある
- タプル構造体、一般的にはタプル
- 古典的なC言語的な構造体
- ユニット、フィールドを持たない、ジェネリックスな使用用途
ソースコード
ソースコード
#![allow(dead_code)]
use std::fmt;
#[derive(Debug)]
struct Person {
name: String,
age: u8,
}
struct Unit;
struct Pair(i32, f32);
struct Point {
x: f32,
y: f32,
}
struct Rectangle {
top_left: Point,
bottom_right: Point,
}
fn rect_area(rect: Rectangle) -> f32 {
let Rectangle {
top_left: Point {x: p1_x, y: p1_y },
bottom_right: Point {x: p2_x, y: p2_y }
} = rect;
let height = if p1_y > p2_y {p1_y - p2_y} else {p2_y - p1_y};
let width = if p1_x > p2_x {p1_x - p2_x} else {p2_x - p1_x};
height * width
}
fn square(p: Point, f: f32) -> Rectangle {
Rectangle {
top_left: Point { x: p.x, y: p.y },
bottom_right: Point { x: p.x + f, y: p.y + f }
}
}
impl fmt::Display for Rectangle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "P1({}, {}), P2({}, {})",
self.top_left.x,
self.top_left.y,
self.bottom_right.x,
self.bottom_right.y,
)
}
}
fn main() {
let name = String::from("Peter");
let age = 25;
let peter = Person { name, age };
println!("{:?}", peter);
let point: Point = Point { x: 10.0, y: 10.0 };
let another_point: Point = Point { x: 15.0, y: 15.0 };
println!("point coordinates: ({}, {})", point.x, point.y);
let bottom_right = Point { x: 4.0, ..another_point };
println!("second point: ({}, {})", bottom_right.x, bottom_right.y);
let Point {x: left_edge, y: top_edge } = point;
let rectangle = Rectangle {
top_left: Point { x: left_edge, y: top_edge },
bottom_right: bottom_right,
};
let _unit = Unit;
let pair = Pair(1, 0.1);
println!("pair contains {:?} and {:?}", pair.0, pair.1);
let Pair(integer, decimal) = pair;
println!("pair contains {:?} and {:?}", integer, decimal);
println!("Rectangle is {}", rectangle);
println!("Rectangle area is {}", rect_area(rectangle));
let square_info = square(point, 10.0);
println!("Square is {}", square_info);
println!("Square area is {}", rect_area(square_info));
}
出力結果
Person { name: "Peter", age: 25 }
point coordinates: (10, 10)
second point: (4, 15)
pair contains 1 and 0.1
pair contains 1 and 0.1
Rectangle is P1(10, 10), P2(4, 15)
Rectangle area is 30
Square is P1(10, 10), P2(20, 20)
Square area is 100
後書き
ディスプレイ用の処理の書き方がなかなか覚えられないため、要反復練習
型がきちきちに決まっていて、その通りにしか書けないため、コーディングしやすい印象でした