| Rust 人門 |
ここではRustの新奇性のみにしぼって解説する。 実際的なこと(インストール方法とか)は説明しない。
fn main() {
let x = 2; // これは
let y = 3; // コメント
println!("x+y={}", x+y);
}
! がつくものはマクロ (hygienic) である。
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x:2, y:3 };
println!("p={},{}", p.x, p.y);
}
i32 = int
p はスタック上に存在。
fn main() {
let q = Box::new(Point { x:2, y:3 });
println!("q={},{}", (*q).x, (*q).y);
println!("q={},{}", q.x, q.y); // OK
}
Box::new() = 基本的に malloc。
* で解決する。
main() {
file f("hello.txt"); // ファイルが開かれる。
string s(f.read()); // 文字列が初期化される。
cout << s << endl;
// f, s が自動的に解放される。
}
fn main() {
{
let q = Box::new(Point { x:2, y:3 });
println!("q={},{}", q.x, q.y);
// q は勝手に解放される。
}
println!("q={},{}", q.x, q.y); // ERROR
}
fn main()
{
let s = Some(Point { x:2, y:3 });
// または s = None;
match s {
Some(p) => println!("p={},{}", p.x, p.y),
None => println!("p=null"),
}
}
nilかどうか」しか判定できない。
let s: Point?
if let p = s {
print("p=\(p.x),\(p.y)")
} else {
print("p=null")
}
show(Point* p) {
printf("p=%d,%d\n", p->x, p->y);
delete p;
}
main() {
Point* p = new Point(2, 3);
show(p);
delete p; // Double free
}
fn show(p: Box<Point>) {
println!("p={},{}", p.x, p.y);
// RAIIにより勝手に解放される。
}
fn main() {
let p = Box::new(Point { x:2, y:3 });
show(p); // pの所有権がshowに移る。
}
free する責任。
fn show(p: Box<Point>) {
println!("p={},{}", p.x, p.y);
}
fn main() {
let p = Box::new(Point { x:2, y:3 });
show(p);
// この時点で、pはすでにmainのものではない。
println!("area={}", p.x * p.y); // ERROR
}
fn alloc() -> Box<Point> {
let p = Box::new(Point { x:2, y:3 });
// 所有権を返す。
return p;
}
fn main() {
let p = alloc(); // 所有権を得る。
println!("p={},{}", p.x, p.y);
// RAIIにより解放。
}
fn show(p: &Box<Point>) { // pは借り物。
println!("p={},{}", p.x, p.y);
}
fn main() {
let p = Box::new(Point { x:2, y:3 });
show(p); // 貸しただけ。
println!("area={}", p.x * p.y);
// 所有者はまだ俺だから解放しなきゃ。
}
& がついた型は「借り物 (borrow)」であることを表す。
fn area(p: Box<Point>) -> i32 { // 本物
return p.x * p.y;
}
fn show(p: &Box<Point>) { // 借り物
println!("p={},{}", p.x, p.y);
// 借り物を本物として渡そうとすると
println!("area={}", area(p)); // ERROR
}
fn main() {
let p = Box::new(Point { x:2, y:3 });
show(p);
}
fn main() {
let p = Point { x:2, y :3 };
println!("p={},{}", p.x, p.y);
let q = p;
println!("area={}", q.x * q.y); // OK
println!("area={}", p.x * p.y); // ERROR
}
class Foo {
Point* p;
public:
Foo(Point* p) {
this->p = p;
}
};
main() {
Point* p = new Point(2,3);
Foo* foo = new Foo(p);
delete p;
// foo->p は Dangling
}
struct Foo {
pt: Box<Point>, // 所有権をもつ。
}
fn main() {
let p = Box::new(Point { x:2, y:3 });
// pの所有権は foo内に移動する。
let foo = Foo { pt:p };
// もう p は俺の物じゃない。
println!("p={},{}", p.x, p.y); // ERROR
// fooが解放されると p も解放される。
}
struct Foo {
pt: &Box<Point>, // 借り物
}
fn alloc(&Box<Point>) -> Foo {
return Foo { pt:p }; // 借り物が入った本物
}
fn main() {
let p = Box::new(Point { x:2, y:3 });
let foo = alloc(&p);
println!("p={},{}", p.x, p.y); // OK...のはず
}
// 実際にはコンパイル不可
struct Foo {
pt: &Box<Point>, // 借り物
}
Foo 型は限られた期間だけ有効。
Foo はパラメータ化された型なのである。
struct Foo<'a> {
// pt は、少なくとも Foo本体と期間は生きる。
pt: &'a Box<Point>,
}
// 「与えられた p と同じ期間は生きる Foo」を返す。
fn alloc<'a>(p: &'a Box<Point>) -> Foo<'a> {
return Foo { pt:p };
}
'a, 'b のように表す。
(型をさらに限定するという意味で <...> が使われている。)
&)」に対してのみ。
fn main() {
let p = Box::new(Point { x:2, y:3 });
let foo = alloc(&p); // p と同じ生存期間をもつ。
println!("p={},{}", p.x, p.y);
}
struct Foo<'a> {
pt: &'a Box<Point>,
}
// 簡略版。
fn alloc(p: &Box<Point>) -> Foo {
return Foo { pt:p };
}
Foo 構造体の定義では省略不可)
// 「与えられた p と同じ期間は生きる Foo」を返す。 // でも q は関係ないので別の生存期間。 fn alloc<'a>(p: &'a Box<Point>, q: &'b Box<Point>) -> Foo<'a> { println!("q={},{}", q.x, q.y); return Foo { pt:p }; }
channel … メッセージ送受信に使う。
一旦メッセージを送ったら、そのデータの所有権は移動する。
ARC … 借り物を共有するときに使われる
排他制御 + 参照カウンタつきスマートポインタ。
RC … 所有権を移動するときに使われる
参照カウンタつきスマートポインタ。
unsafe { ... } で囲んだ部分は、所有権・生存期間の規則を無視できる。