Syntax and Semantics
Rustのsyntaxとsemanticsについて、いくつか細かい事項をまとめて紹介します。
const and static
Const変数とstatic変数は、定数を記述するためのものです。
letでもmutをつけなければ定数ですが、const, static変数はグローバルに宣言できます。
const
constは、コンパイル時定数です。
const N: i32 = 5;letと違って、型を明示する必要があります。
Constな変数は、それを使うところにinline展開されます。
つまり、Nはすべて5に置き換えられるということです。
よって、constな変数はメモリ上に配置されたりしません。
一方、staticはメモリ上に置かれ、'static lifetimeをもちます。
よって、static変数へのアクセスは、すべておなじメモリ上の値へのアクセスになります。
あたり前のことですが、const, static変数ともに、初期値が必要です。
実は、static変数はmutをつければmutableになります。
ただし、mutableなstatic変数へのアクセスは安全性が保証されないので、
unsafeブロック内でおこなう必要があります。
使わないに越したことはない、ということですね。
定数を使いたいほとんどの場合はconstを使っておくのがよさそうです。
Attributes
これまでも#[derive(Debug)]とかが登場していましたが、これを’attribute’といいます。
コードになんらかの性質をもたせるものです。
Attributeの書きかたには二種類あり、
#[foo]
struct Foo;
mod bar {
#![bar]
}のように、!をつけない#[foo]と、つける#![bar]があります。
!をつけないほうは、そのattributeの直後のものについて作用するのに対し、
!をつけるほうは、そのattributeがかかれているもの(ここではmod bar)について作用します。
違いはこれだけです。
どんなattributeがあるのかというと、たとえば
#[test]
fn check() {
assert_eq!(2, 1 + 1);
}というのがあります。
関数に#[test]attributeをつけると、その関数はテスト用の関数となり、
テスト時に実行されます。
他には、inline展開を指定する(もっともinline展開の判断はコンパイラに任せるべきですが)
#[inline(always)]
fn super_fast_fn() {や、コンパイル条件を設定する
#[cfg(target_os = "macos")]
mod macos_only {というのがあります。 ほかのattributeについては、 公式リファレンス を読むのがいいでしょう。
type aliases
typeは型に別名をつけるものです。
C++でいうusingエイリアスです。
以下のように使います。
type Name = String;
let x: Name = "Hello".to_string();似たようなものに、要素が一つのtuple structがありました。
要素が一つのtuple structは、別の型をつくった(newtype)のに対し、
typeエイリアスはただの別名です。
Casting Between Types
Rustは強い静的型付き言語ですが、型変換もできます。 方法は二通りあります。
as
asキーワードをつかうと、ちゃんと型変換できるかコンパイラがチェックしてくれて、
安全にキャストできます。
let x: i32 = 5;
let y = x as i64;transmute
transmuteは、型チェックせず、bit列をほかの型として解釈し直します。
unsafeブロック内でしか使えません。
危険なのでできるだけ使いたくないものです。
たとえば、8bit x 4つの配列をu32に解釈しなおすコードは次のようになります。
use std::mem;
unsafe {
let a = [0u8, 0u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u32>(a);
}transmuteをつかっても、サイズのチェックくらいはしてくれるそうです。
たとえば先ほどの配列aをu64にtransmuteすることはできません。
Unsized Types
Rustではほとんどの型はサイズがコンパイル時にわかっています。
例えばi32は32bitという具合です。
しかし、いくつか可変長な型もあります。
そのひとつが[T]で、これはT型がいくつか並んだものです(固定長配列[T; N]とは違います)。
メモリ上の連続した領域に配置されているようです。
安全なプログラムを目指すため、Rustで可変長型をつかう際には制限があります。
- 可変長型の操作はすべてポインタを通しておこないます。
つまり
[T]ではなく&[T]です。 - Variableや引数には使えません。
- Structの要素に含めるときは、最後のフィールドでなければなりません。
- Enumは可変長型を要素にもてません。
?Sized
ジェネリックなstructや関数をつくると、
型パラメータには暗黙的に、Sizedtrait制約がつきます。
そのため、Sizedtraitをもっていない型を受け付けることはできません。
この制約を外すのが?Sizedです。
struct Foo<T: ?Sized> {
f: T,
}上のように、?Sizedという(擬似?)traitを要求しておくと、
SizedでないものもTとすることができます。