構造体を定義する
構造体を定義
構造体の定義はstructキーワードのあとに構造体の名前を付け、波かっこの中にフィールドを型名、名前の順で書いていきます。以下に複素数を表現する構造体の例を示します。
struct Complex{
f64 re,
f64 im
}
reには実部、imには虚部を格納します。
インスタンスを生成
定義した構造体名は型名としても使えて、その型名で変数を宣言することで実体を持ったインスタンスを生成します。また、これだけではフィールドに値が入ってないのでそれぞれ値を代入していく必要があります。
struct Complex{
f64 re,
f64 im
}
fn main():i32{
#=(c, _, Complex);
=(.(c,re),1.0);
=(.(c,im),2.0);
println(format("c = %g + %gi",.(c,re),.(c,im)));
return 0s
}
c = 1 + 2i
フィールドへのアクセスは.(インスタンス,フィールド名)でできます。
しかし、これを毎回やっていてはコードが長くなってしまいます。そこで、フィールドの値を引数で渡して一括で代入してくれる関数を作ると便利です。
fn Complex_new(f64 re,f64 im):Complex{
#=(cplx, _, Complex);
=(.(cplx,re), re);
=(.(cplx,im), im);
return cplx;
}
このような関数を用意しておくと
#=(c, Complex_new(1.0,2.0), Complex);
とするだけで先ほどのようにComplexのインスタンスを簡単に生成できます。
フィールドにアクセス
先ほども述べたように構造体のフィールドへのアクセスは.(インスタンス,フィールド名)でできますが、構造体はポインタで扱うことも多いので、インスタンスのポインタを使ってアクセスする方法が二つあります:_>(インスタンスのポインタ,フィールド名)と->(インスタンスのポインタ,フィールド名)です。_>はインスタンスのポインタからフィールドの値を返し、->はインスタンスのポインタからフィールドのポインタを返します。
| アクセス方法 | 第一引数 | 戻り値 |
|---|---|---|
| . | インスタンスの値 | フィールドの値 |
| _> | インスタンスのポインタ | フィールドの値 |
| -> | インスタンスのポインタ | フィールドのポインタ |
構造体での所有権
フィールドが所有権を持つ構造体を作ることができますが、そのような構造体は所有権チェックを受けらないためメモリ安全が担保されません。そのため解放する関数を構造体に対して定義して解放忘れがないように注意してください。また、ヒープ領域とスタック領域のどちらでも受け入れる場合は型を&mut:Tまたはptr:Tにしてヒープ領域の場合は別で所有者を設けてメモリの管理をすることを推奨します。
struct Parson{
*:char name, // nameが所有権を持つ
i64 age,
}
fn Parson_free(ptr:Parson p){
free(pmove(_>(p,name))); // nameを解放
}
fn Parson_new(*:char name, i64 age):Parson{
#=(parson, _, Parson);
=(.(parson,name),pmove(name)); // 所有権が構造体のフィールドに譲渡される
=(.(parson,age),age);
return parson;
}
fn main():i32{
#=(name,malloc(6,char),*:char);
memcpy(name,"Kazane",6); // ヒープ領域に文字列をコピー
#=(p,Parson_new(pmove(name),19),Parson);
println(format("name: %s\nage %d",.(p,name),.(p,age)));
Parson_free(&_(p)); // 解放
return 0s;
}