dunno logs

神山生活四年目

Ruby でもメソッドをブロックの代わりに渡したい

C# でコードを書いていると以下のようなコードを R# がよく薦めてきます。(久しぶりに C# 書いたけど、これで合ってるかな。。)

// 前提
var list = new[] {1, 2, 3, 4};

private int Method(int) {
  // なんか処理して int を返す
}

// before
list.Select(x => Method(x));

// after
list.Select(Method);

ここで使ってる SelectIEnumerableメソッドですが、引数は System.Func<TSource, TResult>delegate となっています。

after のようにできるのは、その delegateシグネチャが一致しているメソッドであれば同じように扱えるという仕様を利用しています。

Ruby の Symbol#to_proc

RubySymbol#to_proc があるので配列の各要素のメソッドを以下のように呼び出せます。

list = [1, 2, 3, 4]

list.map(&:to_s) # 単に数値を文字に変えるだけですが、int の to_s メソッドを呼び出している。
=> ["1", "2", "3", "4"]

これは Ruby を使い出してすごい便利と思った機能だったのですが、一方で C# のようにメソッドを渡せないのかなぁと思ってました。

def double(num)
  num * 2
end

list.map {|num| double(num) }

# これを list.map(double) ぐらいで書きたい

Method は to_proc できるらしい

Object#method で Method のオブジェクトにできるので

double_method = method(:double)
=> #<Method: Object#double>

double_method.to_proc
=> #<Proc:0x007fb79abcf0d0 (lambda)>

list.map(&double_method)
# or
list.map(&method(:double))

ちょっと冗長に見えるけど、少しだけ C# の書き方に近い感じになって嬉しい。でも method を呼び出すのは、ちょっと微妙っちゃ微妙ですよね。。

参考リンク