圧倒亭グランパのブログ

30年後の自分にもわかるように書くブログ

Crystalのmacro紹介 "record"

この記事は、 Crystal Advent Calendar 2017 の5日目の記事です。

crystalには便利なmacroがあります。macroを使えば、記述量も削減でき表現力も向上します。しかし、ただcrystalを書いているだけでは、なかなかそれらのmacroに出会うことができません。

ということで、アドベント・カレンダーの日数稼ぎも兼ねて、macroの紹介をしたいと思います。

そもそも「macroってなんだ」という場合は、下記の本家docsを参照してください。

Macros · GitBook

 

今回は、 record を紹介します。

record

crystal-lang.org/api - Top Level Namespace - record

Struct を簡単に記述できるmacroです。シグネチャは以下です。

macro record(name, *properties)

通常、Structの定義はこうです。

# Structの定義
struct User1
  property name : String
  property age : Int32

  def initialize(@name, @age)
  end
end

user1 = User1.new "Taro", 30

p user1      # => User(@age=30, @name="Taro")
p user1.name # => "Taro"
p user1.age  # => 30

これをmacroのrecordを使うとこうなります。

# Structの定義
record User2, name : String, age : Int32

user2 = User2.new "Taro", 30

p user2      # => User(@age=30, @name="Taro")
p user2.name # => "Taro"
p user2.age  # => 30

1行で定義が書けてしまいました。

メソッドを定義する場合は、blockを用います。

# Structの定義
record User3, name : String, age : Int32 do
  def greeting
    "Hello!"
  end
end

user3 = User3.new "Taro", 30

p user3          # => User(@age=30, @name="Taro")
p user3.name     # => "Taro"
p user3.age      # => 30
p user3.greeting # => "Hello!"

propertyの初期値も設定できます。

# Structの定義
record User4, name : String = "Taro", age : Int32 = 30

user4 = User4.new

p user4      # => User(@age=30, @name="Taro")
p user4.name # => "Taro"
p user4.age  # => 30

初期値から、型の推論も行ってくれます。

# Structの定義
record User5, name = "Taro", age = 30

user5 = User5.new

p user5      # => User(@age=30, @name="Taro")
p user5.name # => "Taro"
p user5.age  # => 30

ちょっとしたStructなら、recordを使うとスッキリ書けますね。

ぜひ使ってみてください。