Crystalのmacro紹介 "def_equals"
この記事は、 Crystal Advent Calendar 2017 の6日目の記事です。
crystalには便利なmacroがあります。macroを使えば、記述量も削減でき表現力も向上します。しかし、ただcrystalを書いているだけでは、なかなかそれらのmacroに出会うことができません。
ということで、アドベント・カレンダーの日数稼ぎも兼ねて、macroの紹介をしたいと思います。
そもそも「macroってなんだ」という場合は、下記の本家docsを参照してください。
今回は、 def_equals
を紹介します。
def_equals
crystal-lang.org/api - Object - def_equals
オブジェクトの同値性比較を行う ==
メソッドを定義します。この==
メソッドは、
引数に与えたfieldに対して `==` での比較をし、全てtrueならtrueを返す
というものです。コードで見てみましょう。
通常、==
の定義はこうです。
struct User def initialize(@name : String, @age : Int32) end # 同値性比較のメソッドを定義 def ==(other : self) return false unless @name == other.@name return false unless @age == other.@age true end end user1 = User.new "Taro", 30 user2 = User.new "Taro", 30 p user1 == user2 # => true
これをmacroのdef_equals
を使うとこうなります。
struct User def initialize(@name : String, @age : Int32) end # 同値性比較のメソッドを定義 def_equals @name, @age end user1 = User.new "Taro", 30 user2 = User.new "Taro", 30 p user1 == user2 # => true
とても簡単ですね。macro素晴らしい。
def_hash
同値比較がtrueを返すオブジェクト同士でも、それらがhashのkeyとして扱われた場合、「keyとして同値」とは判定されません。
class User def initialize(@name : String, @age : Int32) end # 同値性比較のメソッドを定義 def_equals @name, @age end user1 = User.new "Taro", 30 user2 = User.new "Taro", 30 p user1 == user2 # => true hash = {user1 => 1} p hash.has_key?(user2) # => false
keyの比較には#hash
メソッドが使用されるからです。そんな時は def_hash
macroを使いましょう。
lass User def initialize(@name : String, @age : Int32) end # 同値性比較のメソッドを定義 def_equals @name, @age # #hashメソッドを定義 def_hash @name, @age end user1 = User.new "Taro", 30 user2 = User.new "Taro", 30 p user1 == user2 # => true hash = {user1 => 1} p hash.has_key?(user2) # => true
比較できるようになりました。
def_equals_and_hash
同値性やkeyの比較は、一緒に実装することが多いでしょう。そんな時は def_equals
とdef_hash
の両方の意味を持つ def_equals_and_hash
を使います。
class User def initialize(@name : String, @age : Int32) end # 同値性 & key比較 def_equals_and_hash @name, @age end user1 = User.new "Taro", 30 user2 = User.new "Taro", 30 p user1 == user2 # => true hash = {user1 => 1} p hash.has_key?(user2) # => true
簡単に定義できました。
ぜひ使ってみてください。