レコード型

リストやタプル、配列といったデータ構造について説明してきましたが この他に、F#にはレコードというデータ構造があります。 レコードではいくつかの値を並べることでデータを表現し、 それぞれのデータに名前をつけられる点に特徴があります。 これはC言語でいえば構造体に相当するものですが F#ではC言語ライクな構造体の表現法は別にあります。 これについてはオブジェクト指向の部分で説明します。 基本的なレコードの構文は次のようになります
レコードの定義
type 型名 = { フィールド名1 : 型名1; ... ; フィールド名n : 型名n }
レコードの値の作成
{フィールド名1 = 式1; ... ; フィールド名n = 式n}
例として、商品名と値段のフィールドを持つjuice型の定義です。
レコード型の定義
type juice = {name : string;price : int};;
この型のデータを定義すると次のようになります。
レコード型の値
let my = {name = "Mellow Yellow";price = 110};;
let dp = {name = "Doctor Pepper";price = 120};;
また、既存のデータを使って新しいデータを定義することも出来ます。 構文は次の通りです この構文はコピーと更新のレコード式と呼ばれます。
コピーと更新のレコード式(既存レコードからのレコード作成)
{ 既存レコード with フィールド名1 = 式1; ... ; フィールド名n = 式n }
これを用いた例は次の通り
既存レコードからレコードを作る
let ab = { my with name = "Ambasa" };;
レコードから値を取り出すには、 レコード型の変数名.フィールド名のようにします。
レコードからの値の取り出し
> my.name;;
val it : string = "MellowYellow"
> ab.price;;
val it : int = 110
レコードに関して気をつけるべきことがあります。 それは、上記のような状態で次のような新しいレコードを定義したとします。
既存のレコードとかぶったフィールド名のレコード
type goods = {name : string;price : int};;
let my_oyatu = {name = "peranperan";price = 30};;
これは先ほど定義したjuice型と同じフィールド名を持っています。 この時、my_oyatuはjuice型ではなく、goods型となってしまいます。 つまり、新しく定義したレコードのフィールド名は 既存のレコードとかぶらないよう注意する必要があります。 このような点を考えると、ある程度の規模の開発でレコード型を使うのは 難しいのでは無いかと思います。 既存のレコードとフィールド名がかぶっていないことを意識しながら レコードを使うというのは大変だからです。 レコード型の値も、基本的には一度定義したら 値は変更できないのですが mutableキーワードをつけることで値を変更可能に出来ます。 この時、値を変更するには<-演算子を使います。
mutableなレコード
type human = {name:string;mutable age: int};;
let nobita = {name = "nobi nobita"; age = 11};;
let time_furosiki (x:human) = x.age <- x.age + 10;;
time_furosiki nobita;;
print_int nobita.age;;
名前も結婚で変わる可能性はありますが、 ここでは年齢だけが変更できるhumanクラスを定義しています。 wikiによると、のび太は10年ほど無人島に家出した経験があるらしいので このプログラムでは、タイムふろしきでのび太の年齢に補正をかけています。 レコードの正確な構文は次のようになります。 これからもわかりますが、レコードはメソッドなども持つことができます。 これについてはメソッドのページでも説明します。 []で囲まれた個所は省略できます。
レコードの構文(参考)
参考より [ attributes ] type [accessibility-modifier] typename = { [ mutable ] label1 : type1; [ mutable ] label2 : type2; ... } [ member-list ] f#4.1 spec 8より record-type-defn := type-name = '{' record-fields '}' type-extension-elementsopt type-extension-elements := with type-defn-elements end type-defn-elements := type-defn-element ... type-defn-element type-defn-element := member-defn interface-impl interface-spec member-defn := attributesopt staticopt member accessopt method-or-prop-defn -- concrete member attributesopt abstract memberopt accessopt member-sig -- abstract member attributesopt override accessopt method-or-prop-defn -- override member attributesopt default accessopt method-or-prop-defn -- override member attributesopt staticopt val mutableopt accessopt ident : type -- value member additional-constr-defn -- additional constructor interface-impl := interface type object-membersopt -- interface implementation object-members := with member-defns end member-defns := member-defn ... member-defn interface-spec := interface type