レコード型
リストやタプル、配列といったデータ構造について説明してきましたが
この他に、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