GhaSShee


Rust


# OS in Rust see here * https://os.phil-opp.com * # enum ## `to_owned()` creates an `owned String` e.g. ~~~rs "hello".to_owned() ~~~ # Getting started http://doc.rust-lang.org/book/getting-started.html 1. install `multirust` ~~~sh //@linux 


curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sh //@osx

 brew update && brew install multirust multirust default stable ~~~ 2. start with - `cargo new ProjectName --bin` - `cargo new LibraryName` - `Cargo.lock` : keeps track of dependencies in your application ## guess_game ~~~rs match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => println!("You win!"), } ~~~ * `cmp()` can be called on anything that can be compared * `cmp()` takes a “reference” to the thing you want to compare it to * `cmp()` returns the “Ordering type” instance Ordering is an enum, short for ‘enumeration’, which looks like this: ~~~rs let guess: u32 = guess.trim().parse() .expect("Please type a number!");


 ~~~ - `trim()` on Strings eliminate any white space at the beginning and end of our string - in `read_line()` if we type 5 and hit return, guess looks like `5\n` - `trim()` gets rid of this, leaving our string with only the `5` ~~~rs let guess: u32 = guess.trim().parse() .expect("Please type a number!");



let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, }; ~~~ two err handlings # Viriable Bindings https://doc.rust-lang.org/book/variable-bindings.html ## immutables ~~~rs let x = 5;
 let (x,y) = (1,2); // x = 10; // -> Err let x = 10; // -> OK ~~~ - adding `let` bindings, we can overwrite ## mutable ~~~rs let mut x = 5; // x is mutable x = 10; // OK ~~~ ## scope 2 easy example of scopes ~~~rs fn scope() { let x: i32 = 17; { let y: i32 = 3; println!("x is {} and y is {}", x, y); } // println!("x is {} and y is {}", x, y); // -> Err } ~~~ ~~~rs fn scope2() { let x: i32 = 8; { println!("{}",x); let x = 12 ; println!("{}",x); } println!("{}",x); let x = 42; println!("{}",x); } ~~~ # Functions ## arguments' type are musts ~~~rs fn print_sum(x,y) {
 println!(“sum is: {}”, x + y);
 }
 // this does not work ~~~ - Unlike let bindings - you must declare the type of function arguments !!! 
## returning ~~~rs fn add_one (x:i32) -> i32 { x+1 } 
// -> i 32 shows returning a i32 typed value 
// the statement without ; is return value ~~~ ## expressions vs. statements * Ruby can be like this:
`x = y = 5` - in Rust , using let to introduce a binding is not an expression !!
- “ let “ can only begin a statement , not an expression !! ~~~rs fn expr() { let mut y =5; let x = ( y = 6 ) ; // x has the value `()` not `6` println!("{:?},{}" , x, y); } ~~~ ## Early Returns ~~~rs 

fn foo(x: i32) -> i32 { return x ; 
 // never run below x = x + 1; } ~~~ ## Higher Order Functions ### this works ~~~rs fn higherOrder() { let x = (0..).map(|n| n*n) .take_while(|&n| n < 1000) .filter(|n| is_odd(*n)) .fold(0, |sum,i| sum + i); println!("{:?}" ,x); } ~~~ ### not work ~~~rs fn higherOrder() { let x = (0..).map(|n| n*n) .take_while(|&n| n < 1000) .filter(|n| is_odd(*n)); println!("{:?}" ,x); } // this does not work ~~~ ## Function Pointers ~~~rs 

let f = add_one;
 // or if add_one is without type
 // let f: fn (i32) -> i32 = add_one;
let six = f(5);


 ~~~ # Primitive Types https://doc.rust-lang.org/book/primitive-types.html ## Types char : 4bytes pointer sized signed integer
usize IEEE754 ~~~rs rustc —version
cargo new projectName —bin ~~~ types - isize : depends on the size of a pointer of the underlying machine ~~~ let a = [1,2,3]; // immutable
let mut a = [1,2,3] //mutable ~~~ ~~~ cargo new primitive_types --bin ~~~ ~~~ let a = [0; 20]; // [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ~~~ ## Raw Pointer as で取りださないと新しいアドレスは割り当てられない ~~~rs let x = 5; let raw = &x as *const i32; let mut y = 10; let raw_mut = &mut y as *mut i32;Run However, dereferencing one is not. This won’t work: let x = 5; let raw = &x as *const i32; println!("raw points at {}", *raw); It gives this error: error: dereference of raw pointer requires unsafe function or block [E0133] println!("raw points at {}", *raw); ^~~~ When you dereference a raw pointer, you’re taking responsibility that it’s not pointing somewhere that would be incorrect. As such, you need unsafe: let x = 5; let raw = &x as *const i32; let points_at = unsafe { *raw }; println!("raw points at {}", points_at); ~~~ | c | rust | | :---: | :---: | | `T*` | `*mut T` | | `const T*` | *const T | Rust ~~~rs // explicit cast let i: u32 = 1; let p_imm: const u32 = &i as const u32; // implicit coercion let mut m: u32 = 2; let p_mut: *mut u32 = &mut m; unsafe { let ref_imm: &u32 = &*p_imm; let ref_mut: &mut u32 = &mut *p_mut; } ~~~ ~~~ &*&rawだとrawがでた ~~~ c ~~~c int x = 5; // x = (ad_1 :Addr , val_1 :Int) int* p // p = (ad_2 :Addr , _ :Addr) p = &x // p = (ad_2 :Addr , ad_1 :Addr) int** ppx = &&x; // let &x = (ad_3 :Addr, ad_1:Addr) in // ppx = (ad_4 :Addr, ad_3:Addr) int& a ; // error '&' is not injective ~~~ ## 参照渡し http://www.asahi-net.or.jp/~yf8k-kbys/newcpp_ho3.html &が付くと参照渡しに 操作するものは変数の左に、 宣言は型の右に という感じかな? 一番上は値渡しで&がつくと参照渡しですね - v : 自由変数 - x : 束縛変数 - 値渡し : 関数を作るときにスタックがまず作られます、そこに束縛変数(関数内のみの変数)が作られて、 その束縛変数に値が入る。なのでスタックの消滅とともに、束縛変数は消滅する ~~~rs int i = 10; char c = 'c'; void* a = &i; a = &c; ~~~ Cだとキャストなしで行けたかな? ~~~c sizeof int // 4 sizeof char // 1 sizeof void* // 4 sizeof int* // 4 sizeof char* // 4 // (32bit環境) ~~~ ## bad example owing to `{:?}` Rust ~~~rs let x = 5; println!("{:?}",x); // 5 println!("{:?}",&x); // 5 println!("{:?}",***&&&&&&&x); // 5 ~~~ C &&&&xのアドレスが表示される ~~~ p -> p -> p -> p -> x ^ | ここを表示 ~~~ - "{:?}" で出力しているから変な事になっていたようで、"{:p}"だと素直になりました - `&` だけでもポインタはとれていたようです ## back from pointers ~~~ `&&&x`を直接出力した場合、同じ物を出力した場合でも値が変わったので、 `&`で取るたびに新しいアドレスが割り当てられるようです `cout >> `を採用していないのは、そういうことだったのでしょうね ~~~ ## slice ~~~rs let a = [0, 1, 2, 3, 4]; let complete = &a[..]; // A slice containing all of the elements in a let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3 ~~~ ## string see the string chapter and reference chapter ## tuple ~~~rs let x: (i32, &str) = (1, "hello"); // here , “hello” is referenced that is why typed &str ~~~ You can access the fields in a tuple through a destructuring let. Here’s an example: ~~~rs let (x, y, z) = (1, 2, 3); println!("x is {}", x); // パターンマッチングも使えるよ!
 // 要素一つのタプルも作れるよ! 
(0,); // single-element tuple (0); // zero in parentheses ~~~ tuple indexing ~~~rs let tuple = (1, 2, 3); let x = tuple.0; let y = tuple.1; let z = tuple.2; println!("x is {}", x); ~~~ ## functions Functions also have a type! They look like this: ~~~rs fn foo(x: i32) -> i32 { x } let x: fn(i32) -> i32 = foo; ~~~ # Comments https://doc.rust-lang.org/book/comments.html ~~~ お疲れ様でした。すみませんちょっと呼び出しされてました お疲れ様でした。 ドラゴンブックより抜粋 左辺値と右辺値 識別子は代入文の左辺に現れる場合と、右辺に現れる場合とで、異なる意味を持つ 代入文 i := 5; i := i + 1; において、右辺は整数値の子弟であるのに対し、左辺に現れるi は値の格納先の指定である 同様にpとq を文字へのポインタとすると p↑ := q↑; において、右辺のq↑は文字の子弟であるのに対し、p↑はその文字の格納先の指定であるlそこで、代入文の左辺と右辺とで、それぞれが意味する値を、左辺値、右辺値とよんで区別する。右辺値はふつう値と考えられているものであり、左辺値は格納場所を表す値である。 ~~~ ~~~rs // : line comments /// : Doc comments ~~~ Documentation can be generated in 2 ways ; * from source code * from standalone markdown How to generate Doc ~~~sh $ rustdoc $ cargo doc ~~~ Doc convention in source code

 ~~~rs /// # Panics 
/// Here write about panics
 /// # Errors 
/// Here write about errors 
/// # Safety 
/// Here write about safety
 /// # Examples 
/// /// Here show example codes 
/// # this line will not be printed 
///
fn some_function( i32: arg ) -> bool {
 // implementation
} ~~~ # if ~~~rs 

if () {

} else if () {

} else {

}
 ~~~ ~~~rs let x = 5; let y = if x == 5 { 10 } else { 15 }; // y: i32 ~~~ # Loop https://doc.rust-lang.org/book/loops.html ~~~rs $ cargo new loop —bin // create new project with name loop


# LOOPS

# loop vim src/main.rs 
fn main() { call_loop(); } fn call_loop(){ loop { println!("Loop Forever!"); } } 
$ cargo run ~~~ ## while ~~~rs 
fn call_while(){ let mut x = 5; let mut done = false; while !done { x += x - 3; println!("{}", x); if x%5==0 { done = true; } } } ~~~ ## for ~~~rs fn call_for() { for i in 0..10 { println!("{}", i); // this prints 0 .. 9 , not 10 } } ~~~ ~~~rs for var in expression { code } ~~~ The expression is an item that can be converted into an iterator using IntoIterator Rust does not have the “C-style” for loop on purpose.
Manually controlling each element of the loop is complicated and error prone, even for experienced C developers. ## Enumerate ~~~rs 
fn call_enumerate() { for (i,j) in (32..40).enumerate() { println!("{}th input is {}", i , j); } } fn call_enumerate2() { let lines = "hello\nworld\nfoo\nbar!".lines(); for (i , line) in lines.enumerate() { println!("{}: {}", i, line); } let chars = "hello world!".chars(); for (i, char) in chars.enumerate() { println!("{}; {}", i, char); } } ~~~ ~~~
rs fn call_label() { 'outer: for i in 0..10 { 'inner: for j in 0..10 { if i%2==0 {continue 'outer;} if j%2==0 {continue 'inner;} println!("{:?}",(i,j)) } } }
 ~~~ # Vectors https://doc.rust-lang.org/book/vectors.html 
vector : dynamic or growable array - it is in standard library. - the type is written as “ Vec ” - where T is any type - Vectors always allocate its data on “ heap “ - we can make vectors with “ vec![] “ macro . ~~~sh 
$ cargo new vector --bin
$ cd vector
$ vim src/main.rs ~~~ ~~~rs fn gen_vectors(){ let v1 = vec![1,2,3,4,5]; let v2 = vec![0;10]; println!("v1:{:?}\nv2:{:?}",v1,v2); } 
v1:[1, 2, 3, 4, 5] v2:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
errors

let v = vec![1, 2, 3]; match v.get(7) { Some(x) => println!("Item 7 is {}", x), None => println!("Sorry, this vector is too short.") }

 ~~~ today's code ( 4.7 vector )

 ~~~rs 

fn main() { iterate(); error(2); gen_vectors(); println!("Hello, world!"); } fn gen_vectors(){ let v1 = vec![1,2,3,4,5]; let v2 = vec![0;10]; println!("v1:{:?}\nv2:{:?}",v1,v2); println!("v1's third element is {}",v1[2]); } fn error(n: usize) { let v = vec![1,2,3]; match v.get(n) { Some(x) => println!("the {}th element is {}", n,x), None => println!("Sorry the length of vector is too short") } //println!("v's 7th element is {}" , v[7]); } fn iterate() { let mut v = vec![6,2,3,4,5]; for i in &v { println!("a reference to {}", i); } for i in &mut v{ println!("a mutable reference to {}", i); } for i in v { println!("take ownership of the vector and its element and no more available orz{}" ,i); } /* for i in &v { println!("no more available because v is garbage collected {}" ,i); } */ } ~~~ # Ownership https://doc.rust-lang.org/book/ownership.html ownership に入ります。rust 独自機能の部分です 
goal of ownership : memory safety 3 chapters here
 - ownership 
- borrowing 
- lifetime
 Many new users to Rust experience something we like to call
‘fighting with the borrow checker’,
where the Rust compiler refuses to compile a program that the author thinks is valid. ownership を理解しないことには、コンパイル時に borrow checker と戦う羽目に陥るそうです。 -
All primitive types implement the Copy trait - vectors have pointer on stack and the data on heap ~~~rs 
$ cargo new ownership --bin fn foo() { let v = vec![1, 2, 3]; } ~~~ When v comes into scope, a new vector is created on the stack, and it allocates space on the heap for its elements. When v goes out of scope at the end of foo(), Rust will clean up everything related to the vector, even the heap-allocated memory. 
vector v allows only 1 ownership !!
like :
 ~~~rs 
fn main() { println!("Hello, world!"); change_ownership(); } fn change_ownership(){ let v = vec![1,2,3,4]; take(v); println!("v[0] is {}" , v[0]); // this cause error !! because v is taken its ownership by fn "take(v)" } fn take(v: Vec) { } ~~~ more explanation ~~~rs 

let x = 10; // Rust allocates memory for an integer [i32] on the stack 


let v = vec![1,2,3]
 // Rust allocates memory for
 // an object pointing data on the stack
 // and for 
// an actual data on the heap

let mut v2 = v;
 // this copies the object on stack
 // 2 pointer into 1 data is so violate that v is deleted here. 
// if we did like below , it would be danger.. v2.truncate(2); 
println!("now v[2] is {}" , v[2]); //
copy Types 

fn copy_types() { let x = 1; let mut x2 = x; // this do copy . not make the same pointing println!("x is {}",x); }

//i32 has no pointers

//For more, if you copy your object see
 ~~~ http://doc.rust-lang.org/book/traits.html # Reference and Borrowing https://doc.rust-lang.org/book/references-and-borrowing.html

Borrowing に入ります。
 Rust は、" zero cost abstraction " によって、安全で速い処理を実現している これは、Rust において、"abstractions" を必要最小限にとどめるようにしようとするもの その最たるものとして、ownership があげられる 
borrowing ! ~~~rs $ cargo new borrowing --bin
$ cd borrowing
$ vim src/main.rs 
We call the &T type a ‘reference’, and rather than owning the resource, it borrows ownership.

There’s a second kind of reference: &mut T. A ‘mutable reference’ allows you to mutate the resource you’re borrowing. --- fn main() { func_1(); println!("Hello, world!"); func_2(); } fn foo (v1: Vec , v2: Vec) -> (Vec, Vec, i32){ (v1,v2,42) } fn func_1() { let v1 = vec![1,2,3]; let v2 = vec![1,2,3]; let (v1,v2,answer) = foo(v1,v2); //println!("{},{},{}",v1,v2,answer); } fn foo2(v : &mut Vec) { v.push(5); } fn func_2() { let mut v = vec![1,2,3]; foo2(&mut v); println!("{:?}",&v); } ~~~ 
borrowing は要約すれば、ownership を拝借する
&T と&mut T の二つの型のことを指しているようです。 これらは参照ですが、mutable な参照とそうでない参照という二種類に分けることができ、
関数を関数プログラミングに組み込む際に必要な機能を見事に実装したものと感じました。 # Lifetimes https://doc.rust-lang.org/book/lifetimes.html ~~~rs // implicit fn foo(x: &i32) { } // explicit fn bar<'a>(x: &'a i32) { } ~~~ this means that x in bar & x in foo has the same lifetime that ends in the end of the function prerequisity ## struct & impl struct defines parameter impl defines methods ~~~rs struct Circle { x: f64, y: f64, radius: f64, } impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); } ~~~ elide : The 't' in 'often' may be elided. ## まとめ borrow するとき、lifetime がコンパイラによって、自動的に設定される 引数として、二つ以上 borrow するときは明示的に return type の lifetime を選んでやる必要がありますが、 以下のように違う引数のものを選ぶとエラーとなる。 ~~~rs fn two_args<'a,'b>(x: &'a i32 , y: &'b i32)-> &'b i32 { &x } fn main() { let a = 999; let b = 888; println!("{}",two_args(&a,&b)); } ~~~ this causes error confliction of lifetime suggesting to use `fn two_args<'a,'b>(x: &'a i32 , y: &'b i32)-> &'a i32` # Mutability mut is part of a pattern e.g. ~~~rs let (mut x, y) = (5,6); // y is not mutable fn foo(mut x: i32) { ... ~~~ one object with two reference ~~~rs use std::sync::Arc; fn func_2(){ let x = Arc::new(5); let y = x.clone(); println!("{},{}",x,y); } // 5,5 ~~~ # Clone , Copy , Drop ~~~rs #[derive(Debug, Clone, Copy)] struct Nil; #[derive(Clone, Debug)] struct Pair(Box, Box); fn main() { let nil = Nil; let copied_nil = nil; let pair = Pair(Box::new(1), Box::new(2)); println!("original: {:?}", pair); let moved_pair = pair; println!("copy: {:?}", moved_pair); // Error! `pair` has lost its resources //println!("original: {:?}", pair); // TODO ^ Try uncommenting this line let cloned_pair = moved_pair.clone(); // Drop the original pair using std::mem::drop drop(moved_pair); // Error! `moved_pair` has been dropped //println!("copy: {:?}", moved_pair); // TODO ^ Try uncommenting this line // The result from .clone() can still be used! println!("clone: {:?}", cloned_pair); } ~~~ the contents of `drop(a)` is done with dropping `a` ~~~rs struct Droppable { name: &'static str, } impl Drop for Droppable { fn drop(&mut self) { println!("> Dropping {}", self.name); } } ~~~ # rust compiler ## lifetime の考察 ライフタイムは型が持つ属性の一つと考えるのがいい。 たとえば参照型 &T と &mut T にはライフタイムが付きます。ライフタイムはコンパイラが推論できるので大半は省略可能。 フィールドとして参照型を持つ struct や enum はライフタイムパラメータが必須。 ~~~rs // ライフタイムパラメータ 'a を持つ型 struct MyStruct<'a> { x: &'a i32, y: &'a str, } // ライフタイムパラメータ 'a と型パラメータ T を持つ型 struct MyGenericStruct<'a, T> { x: &'a T, y: &'a str, } ~~~ スコープは、let binding で実現しているのだという前提で話をすると、 もしローカル変数がライフタイムを持つとすれば、「任意の型がライフタイムを持つ」となります。 https://doc.rust-lang.org/1.9.0/book/lifetimes.html ここにありますように、ライフタイム推論には、local type inference を使っています。 local type はざっくりと「型推論の部分証明木」です。 Local Type Inference (98 Pierce) : https://www.cis.upenn.edu/~bcpierce/papers/lti-toplas.pdf (edited) chapter 1-4 1. 導入、polymorphism , system F などについて 2. F_< の定義、(F_< : ForAll 型のついた system F に対して、部分型を導入したもの) 3. subtype relation において、 普遍性をもつ least super type が存在すれば、local type inference ができるということを理解した。(並びにそれらの定式化) 4. local type inference (synthesis) と global type inference (checking) の融合について理解し、アルゴリズムをさっと見た。通常の型推論にはなぜなかったのかと思えるような機能 (型推論の証明木を上(synthesis)下(checking)に自由に行き来するためのアルゴリズム)が書かれていて非常に勉強になりました。 ライフタイムの実装にも使用されているようで、二、三日寝かせて、関連性を測りたいなと思います。 型推論のところに Subtyping obligations  https://rustc-dev-guide.rust-lang.org/type-inference.html#subtyping-obligations RFC 2094 : ライフタイム推論器のしくみ https://github.com/rust-lang/rfcs/pull/2094 nikomatsakisnikomatsakis #2094 non-lexical lifetimes Extend Rust's borrow system to support non-lexical lifetimes -- these are lifetimes that are based on the control-flow graph, rather than lexical scopes. The RFC describes in detail how to infer these new, more flexible regions, and also describes how to adjust our error messages. The RFC also describes a few other extensions to the borrow checker, the total effect of which is to eliminate many common cases where small, function-local requires would be required to pass the borrow check. (The appendix describes some of the remaining borrow-checker limitations that are not addressed by this RFC.) Due to its size and complexity, this RFC is being run through an experimental process. The text of… Show more Assignees nikomatsakis Labels A-borrowck, A-control-flow, A-machine, A-typesystem, Ergonomics Initiative, T-lang, final-comment-period https://github.com/rust-lang/rfcs 中間言語に関する歴史 Introducing MIR | Rust Blog https://blog.rust-lang.org/2016/04/19/MIR.html ライフタイム推論(リージョン推論) https://ubnt-intrepid.github.io/blog/2017/12/01/rfc-2094-ja/ RFC 2094 (non-lexical lifetime) の非公式訳 本記事は Rust Internal Advent Calendar 2017 第1日目の記事です. 今年の 9/30 に採択された non-lexical lifetimes の RFC である RFC 2094 の非公式訳です. https://doc.rust-lang.org/1.9.0/book/lifetimes.html local type inference を使っている。 local type は「型推論の部分証明木」だとざっくり理解しています。 ## problems of Rust ### unsound hole fn f<'a, 'b, T> (&'b &'a T) では、b を閉じてから、aをとじるものとして推論をするらしい 部分型のread /write に関して contravaiant の方をつかってなんかするバグらしい b をstatic つまり、region を無限大まで広げるなど、 * https://github.com/rust-lang/rust/issues/25860 * https://speakerdeck.com/moratorium08/rustfalseunsound-hole-issue-number-25860woli-jie-suru ### problems of Rust 健全性を証明するのは大変ですからまだ誰もできていないと思いますよ。 健全性は「unsafeのないプログラムは、実際にUBを踏まない」という性質ですが、そもそもUBを踏む条件自体が厳密には定まっていない状況です。 https://github.com/rust-lang/unsafe-code-guidelines/issues この手の検証の最先端はRustBeltチーム http://plv.mpi-sws.org/rustbelt/ のものだと思われますが、 彼らでも「(UBの条件はある程度仮で決めた上で)個別のプログラムがUBを踏まないこと」を検証している段階のはずで、 一般化して議論するのは相当先になるのではないかと思います。 また、健全性を保証するのはコンパイラの責務なのでこの手の問題は最終的には解決されるべきですが、 現実問題として全ての健全性を今すぐ解決するリソースがないのが現状です。 https://github.com/rust-lang/rust/labels/I-unsound%20%F0%9F%92%A5 を見ると、 既知だが解決できていない不健全性は沢山存在していることがわかります。 ## impl の意義 struct と impl を Java では class を使って統一的に分けずに使う慣習もある。 以下の Rust コードにおいては、関数は pure なものなので、 impl が pure な部分だけを切り取るのに都合がよく、 また、c++ user などの需要に応えるべく、abbreviation を置いたと解釈でき、言語設計の経緯が感じられる。 ~~~rs #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Person { name: String, age: u32, } impl Person { pub fn new(name: &str, age: u32) -> Self { Self { name: name.to_owned(), age, } } pub fn name(&self) -> &str { &self.name } pub fn age(&self) -> u32 { self.age } } fn main() { let people = vec![Person::new("Ken", 24), Person::new("Richard", 18)]; // ドットを使った呼び出し dbg!(people[0].name()); // ドット記法は以下の :: を使った呼び出しの省略と見なせる dbg!(Person::name(&people[0])); // `Person::name` 自体が関数なので、以下のようにそのまま高階関数に渡せる let names = people.iter().map(Person::name).collect::>(); dbg!(names); } ~~~ ~~~ Attribute ::= #![ InnerAttr ] | #[ OuterAttr ] ~~~ Rust の `#[...] ` は、総じて、Attribute と呼ばれる。 https://doc.rust-lang.org/reference/attributes.html ## user-defined subtype ? たとえば、Haskell で subtype をユーザ定義したいとき、コンパイラはどのように設計すればよいか。 例えば、NaturalNumbers `N` に対して、EvenNumbers `E` を `N` のsubtype としてユーザーが定義したいような状況です。 コンパイラが型推論に部分型を用いているならば、 部分型をユーザー定義した場合、型推論器の挙動が少し変わってしまう。 subtype をユーザ定義されるような言語の想定される仕様としては、 例えば、Prelude に Set が内包されていると仮定して、subset => subtype という規則が内部言語に存在する subtype relation が Prelude に定義されていて、ユーザ定義されたsubtype relation が内部言語と競合しないことを確かめてからそれらを取り入れる などですが、どちらもふくまれていないように思う。 traitは継承できる (これは、subtype のようなものと言える) ## type lecture by nikomatsakis Ty lecture The many kinds of types - HIR types (rustdoc): describe the syntax of a type - `fn foo(x: u32) → u32 { }` — these two instances of `u32` are distinct HIR types; they have distinct spans, etc - `fn foo(x: &u32) -> &u32)` — the `&` here - `rustc::ty::Ty` (rustdoc): describe the semantics of a type - TyS (rustdoc) - TyKind (rustdoc) fn foo(x: Ty<'tcx>) { match x.sty { } } - There are a lot of related types, we’ll cover these in time - regions (aka, lifetimes) - “substitutions” - etc Interning - We create a LOT of types during compilation - They are allocated from a long-lived arena - and they are canonicalized - CtxtInterners (link) - PartialEq for TyS (link) can just compare pointers - Global <-- types that are global (u32) get allocated here - Type-checking a specific fn - local arena <-- types specific to type-checking Generics and substitutions - Consider this (generic) struct: struct MyStruct { x: u32, y: T } // ^ def_id1 // ^ def_id2 // def_id => "Def path" => crate::foo::MyStruct - A reference to this struct (e.g., `MyStruct`) is as `TyKind::Adt` (link) - `Adt(&'tcx AdtDef, SubstsRef<'tcx>),` - The `AdtDef` defines the struct (`MyStruct`) (enums, unions) - could also be a `DefId`, but the AdtDef struct has useful helper methods - `tcx.adt_def(def_id)` (link) to get one - The `SubstsRef` (link) is an interned list of types (`[u32]`) - `&``'``tcx List>` - `[u32, f32]` — list a - `[f32]` — subslice of a - `[f32]` — list b - `&``'``tcx [Ty<``'``tcx>]` “morally 1.0” - `&``'``tcx [Kind<``'``tcx>]` “morally 2.0” — kinds are either types or regions - well, actually a list of kinds — we’ll come to that - What is the `Generics` struct (link)? - Defines the type parameters Unsubstituted Generics - When inside the scope of a generic definition, generic types are represented by `TyKind::Param` struct Foo { // Adt(Foo, &[Param(0), Param(1)]) x: Vec, // Adt(Vec, &[Param(0)]) .. } // A would have index 0 // B would have index 1 impl Foo { fn method() { // inside here, X, Y and Z are all in scope // X has index 0 // Y has index 1 // Z has index 2 } } fn bar(foo: Foo) { // Adt(Foo, &[u32, f32]) let y = foo.x; // Vec => Vec } - You can get the “self-view” of e.g. a struct using `tcx.type_of(field_def_id)` - in case of `MyStruct`, that would come with a `SubstsRef` that has `TyKind::Param` - You can then `subst` (link) to replace those `Param` with specific types - example of invoking subst (link) - “morally” match t.sty { TyParam(idx, ..) => substs[idx], _ => t.super_fold_with(..) } TypeFoldable Analogy vec.iter().map(|e1| foo(e2)).collect() // ^^^^^^^^^^^^ analogous to folder // ^^^ analogous to "Typefoldable" - `TypeFolder` (link) is a trait that defines a “map” operation: - e.g., `fold_ty` (link) takes a type as input and returns a new type as a result - `TypeFoldable` (link) is a trait that is implemented by things that embed types - it defines a kind of ‘map’ operation, which invokes the `TypeFolder`'s `fold_foo` methods on types, regions, etc that are contained within Typical form: struct MyStruct<'tcx> { def_id: DefId, ty: Ty<'tcx>, } my_struct: MyStruct<'tcx> my_struct.subst(..., subst) impl TypeFoldable for MyStruct { fn super_fold_with(&self, folder: &mut impl TypeFolder<'tcx>) -> MyStruct { MyStruct { def_id: self.def_id.fold_with(folder), ty: self.ty.fold_with(folder), } } fn super_visit_with(..) { } } - Type like `Vec>` - Adt(Vec, &[Adt(Vec, &[Param(X)])]) when substituting X => u32 gives you - Adt(Vec, &[Adt(Vec, &[u32])]) - When you implement this trait, you define how to walk your type and — for each type embedded within — to process them - Macros are sometimes an option: - `BraceStructTypeFoldableImpl` (link) - sometimes subst shuld not have any effect (link) Errors - `Vec<``'``a>` // this would be caught earlier Question: Why not substitute “inside” the adt-def? The adt-def logically represents just the name of the struct (e.g., `Vec`). Its contents are always assumed to be expressed in terms of the “internal” or “self-view” — i.e., expressed in terms of the generics on the struct. If nothing else, this has an efficiency win: struct MyStruct { ... 100s of field .. Vec } MyStruct ==> MyStruct in an example like this, we can subst from `MyStruct` to `MyStruct` (and so on) very cheaply, by just replacing the one reference to `A` with `B`. But if we eagerly substituted all the fields, that could be a lot more work. A bit more deeply, this corresponds to structs in Rust being nominal types — which means that they are defined by their name (and that their contents are then indexed from the definition of that name, and not carried along “within” the type itself). ## arena Crate arena[−][src] [−] The arena, a fast but limited type of allocator. Arenas are a type of allocator that destroy the objects within, all at once, once the arena itself is destroyed. They do not support deallocation of individual objects while the arena itself is still alive. The benefit of an arena is very fast allocation; just a pointer bump. This crate implements TypedArena, a simple arena that can only hold objects of a single type. # favorite iter_of_foo.map(|foo| foo.bar()) の代わりに iter_of_foo.map(Foo::bar) のように書けます LOBPCG法の実装 https://github.com/rust-ndarray/ndarray-linalg/pull/184 #184 Add LOBPCG solver for large symmetric positive definite eigenproblems This PR ports the LOBPCG algorithm from scipy to Rust. The algorithm is useful for the symmetric eigenproblem for just a couple of eigenvalues (for example for multidimensional scaling of gaussian kernels). Solves the issue #160 I did not implement the generalized eigenproblem for matrix B different to identity, as its a uncommon use-case (at least in machine-learning), but if required the modification should be minor. It also adds access to the functions ssygv, dsygv, zhegv, chegv for the generalized eigenvalue problem image with additional mass matrix B. The traits are implemented for tuples of A and B, so you can use it like this let (eigvals, (eigvecs, B_cholesky)) = (A, B).eigh(UPLO::Upper… bokuweb Apr 14th at 2:47 PM GBAで遊んでみました。 lto = true にしないと libunwind をリンクしにいって死ぬという現象が発生したんですが、どう解決すべきものなのか、わかりませんでした。 https://blog.bokuweb.me/entry/2020/04/14/101202 undefinedundefined Rustから目覚めるぼくらのゲームボーイ! - undefined Conway氏についてですが、公式にアナウンスがでたようです。ご冥福をお祈り申し上げます。 www.math.princeton.edu 2003年に発売された「Linuxから目覚めるぼくらのゲームボーイ!」というC言語でゲームボーイアドバンスで動作する自作ゲームを作成していく書籍があります。 ゲームボーイアドバンスはARM7TDMIというコアを使用しており、Rustで自作ゲームを作ることも可能となっています。 この記事では「Linuxから目覚めるぼくらのゲームボーイ!」のステップをRustで実施するための準備としてライフゲームが動くまでを書いてみます。 動機は今作っているWasmインタープリ… https://qiita.com/hatoo@github/items/fa14ad36a1b568d14f3e cargo-snippetでAAを表示しようしたらバックスラッシュの扱いがバグってたので応急処置をした https://github.com/hatoo/cargo-snippet/pull/18 スニペットのアップデートはまだ途中https://github.com/hatoo/competitive-rust-snippets/tree/v1.42 (昔書いたバケット法のコードとかが全く理解できないので整理したい) Rustで競技プログラミング スターターキット - Qiita https://github.com/hatoo/cargo-snippet # warp warp の使い方を見ていました!example 結構あって助かりました。 https://github.com/seanmonstar/warp seanmonstar/warp A super-easy, composable, web server framework for warp speeds. https://seanmonstar.com/post/176530511587/warp https://github.com/seanmonstar/warp termoshtt Apr 4th at 6:54 PM Rustのターゲットとして nvptx64-nvidia-cuda というのがあるので、 cargo build --target=nvptx64-nvidia-cuda でcrateをPTXにコンパイルできる accel-deriveというproc-macroでcargoを起動して、#[kernel] のついた関数をPTXに変換して文字列でソースコードに埋め込んでいる CUDAのAPIを使って文字列になってるPTXをGPU上に読み込んで、同じくCUDAのAPIを使って起動している rust-compiler Compiler Flow https://www.ibm.com/support/knowledgecenter/SSAT4T_16.1.0/com.ibm.xlf161.lelinux.doc/getstart_cudaf/cudaflow.html を参照 The compilation process When CUDA Fortran support is enabled, the compilation process is as follows: Source files, which might contain host code, device code, or both, are processed into the XL intermediate language (W-Code) by the Fortran Frontend (xlfentry) and Transformer (xlfhot). If -O3, -qhot, or -qsmp=omp is in effect, the W-Code is optimized by the High-Level Optimizer (ipa). The W-Code is split into a host W-Code stream and a device W-Code stream by the W-Code intermediate language splitter (partitioner). Host code processing The host W-Code stream is processed into an object file by the Low-Level Optimizer (xlfcode). Device code processing The device W-Code stream is converted to NVVM intermediate representation (NVVM-IR) by the W-Code to LLVM-IR Translator (wc2llvm). The NVVM-IR is converted to PTX (NVIDIA's low-level Parallel Thread eXecution) instructions by the NVVM-IR to PTX translator (llvm2ptx). The PTX instructions are assembled into a device object (cubin) by the PTX assembler (ptxas). The device object is embedded into an object file by the fatbinary tool from the CUDA Toolkit. The object files for the host and device code are combined into a single object file by the host linker (ld). The following diagram shows the compilation process for CUDA Fortran programs. Figure 1. Compilation process for CUDA Fortran programs (edited) rust_mokumoku ubnt-intrepid Apr 4th at 6:06 PM https://github.com/matklad/cargo-xtask#cargo-xtask-ci cargo-xtask は make や npm-scripts のようなプロジェクト固有のタスクを定義する上での枠組みです matklad/cargo-xtask 有名どころだと rust-analyzer というプロジェクトで使用していたりします→ https://github.com/rust-analyzer/rust-analyzer rust-analyzer/rust-analyzer https://rust-analyzer.github.io/ https://github.com/rust-analyzer/rust-analyzer Wasm インタープリタにインポート関数の validation をやる API を実装してました wasmtime のストリーミングコンパイラ lightbeam で使われてるっぽい中間表現 microwasm を眺めてました https://github.com/bytecodealliance/wasmtime/blob/master/crates/lightbeam/src/microwasm.rs crates/lightbeam/src/microwasm.rs https://github.com/bytecodealliance/wasmtime # wasm hiromasa Mar 21st at 1:26 PM .wasm を実行環境する環境によって WebAssembly ランタイムとのインターフェースが異なるイメージになるでしょうか。ウェブブラウザーの場合は ECMAScript 側ではなくブラウザー側の仕様になると思います。 ウェブブラウザーの場合は、JavaScript に対してブラウザーから .wasm をロードしたり関数を呼び出したりするインターフェースが提供されている。https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly (なので、JavaScript を起点としてブラウザーに搭載の WebAssembly ランタイムを利用する) node.js の場合も(やったことないのですが)ウェブブラウザーと同じだと思います。 Wasmer や Wasmtime などの WebAssembly (WASI) ランタイムは .wasm を直接起動できる。(fn main() { } がある。wasmer/hello_world, wasmetime/Running common languages with WASI) 一応、fp-coreというライブラリはありますが、一部は構文上どうしようもないのでマクロに頼るしかないですね Rustは他言語よりも関数型(本格的な)使ってらっしゃる方が多い印象ですが、チーム開発では難しいかもしれませんね… https://github.com/JasonShin/fp-core.rs do記法を再現した便利なマクロもあります https://github.com/TeXitoi/rust-mdo ## concurrency Rust での並列については、イテレータでのストリーム処理の並列化だと rayon がデファクト標準で、 (ちょっと古いかもだけど) 実装者がデザインの解説をしている記事があります: * http://smallcultfollowing.com/babysteps/blog/2015/12/18/rayon-data-parallelism-in-rust/ もっと自由度の高い並列/並行処理については、最近 async / await の言語仕様が安定化されましたが、エコシステムはまだまだ発展途上という感じみたいです。 コア機能については https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html あたりが充実していけば参考になるかもしれません smallcultfollowing.com Rayon: data parallelism in Rust Over the last week or so, I’ve been working on an update to Rayon, my experimental library for data parallelism in Rust. I’m pretty happy with the way it’s b... ## curry / uncurry 手続き型言語のユーザを多数抱える Rust においては、 add(1, 2) を add(1) と書いたとき add(1): i32 -> i32 となるのは喜ばしくなく、 Rust では curry 化をしたくば、コストをかけて ~~~ |n| add(1, n) ~~~ のように書きます。