[Ruby] 式で処理を共通化する方法

Ruby

はじめに

記事を見ていただいて、ありがとうございます!

Webエンジニアをしているsannoと申します。

プログラミング言語を構成する要素には文と式があります。

文と式の意味については、後ほど見ていきますが、特に式について知っているとコードの書き方のレパートリーを増やせます。

今回はRubyの式について解説したいと思いますので、良かったら見ていってください。

環境

p RUBY_VERSION
# 3.2.0

プログラミングの文と式

文と式の意味

文と式の意味についてですが、引用で以下の記事を参考にさせていただきます。

誤解を恐れずに簡単に言ってしまうと、戻り値を使っているものが「式」で、戻り値を捨てているものが「文」になります。

式と文、評価と実行、そして副作用 ―― プログラムはいかにして動くのか【前編】

具体例がほしくなりますね。

例えば、Rubyのifについて見てみましょう。

Rubyのifには文と式の両方の使い方があります。

number = 3
is_divisible_by_three = number % 3 == 0
is_divisible_by_five = number % 5 == 0

# 文のif
if is_divisible_by_three && is_divisible_by_five
  statement_result = 'FizzBuzz'
elsif is_divisible_by_three
  statement_result = 'Fizz'
elsif is_divisible_by_five
  statement_result = 'Buzz'
else
  statement_result = 'Other'
end

p statement_result
# Fizz

# 式のif  
expression_result = if is_divisible_by_three && is_divisible_by_five
                      'FizzBuzz'
                    elsif is_divisible_by_three
                      'Fizz'
                    elsif is_divisible_by_five
                      'Buzz'
                    else
                      'Other'
                    end
                      
p expression_result
# Fizz

文のifと式のifはそれぞれ、上記のようになります。

式のifの方は確かに、ifの戻り値をexpression_resultに格納して使っているのでイメージしやすいですね。

文のifの方は、戻り値を捨てているということになりますがイメージしづらいかもしれません。

文のif をあえて以下のように書き換えてみます。

number = 3
is_divisible_by_three = number % 3 == 0
is_divisible_by_five = number % 5 == 0

# 文のifを書き換え
return_value = if is_divisible_by_three && is_divisible_by_five
                 statement_result = 'FizzBuzz'
               elsif is_divisible_by_three
                 statement_result = 'Fizz'
               elsif is_divisible_by_five
                 statement_result = 'Buzz'
               else
                 statement_result = 'Other'
               end

p return_value
# Fizz

上記のようにifは値を戻しており、上記の例だとFizzを戻しています。

なぜFizzが戻ってきているのかというと、Rubyのマニュアルに以下の説明がありますね。

if 式は、条件が成立した節(あるいは else 節)の最後に評価した式の結果を返します。else 節がなくいずれの条件も成り立たなければ nil を返します。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html

if 式は、条件が成立した節(あるいは else 節)の最後に評価した式の結果を返しますとあるので、statement_result = ‘Fizz’を評価した結果がFizzなので、Fizzが戻ってきているということになります。

初めの文のifに戻りますが、文のifも戻り値はありますが、その値は使わずに捨てているので文になるということです。

number = 3
is_divisible_by_three = number % 3 == 0
is_divisible_by_five = number % 5 == 0

# 文のif
if is_divisible_by_three && is_divisible_by_five
  statement_result = 'FizzBuzz'
elsif is_divisible_by_three
  statement_result = 'Fizz'
elsif is_divisible_by_five
  statement_result = 'Buzz'
else
  statement_result = 'Other'
end

p statement_result
# Fizz

文と式について理解できたところで、次では式を使って処理を共通化する方法について見てゆきたいと思います。

式で処理を共通化をする方法

文と式について理解できたけれど、結局それが何の役に立つのということはありますよね。

文と式を理解するメリットについて、一つの例として処理を共通化することができるということがあります。

先ほどのFizzBuzzの文と式の例がほぼ答えですが、さらにFizzBuzz改造した具体例で見てゆきましょう。

先ほどのFizzBuzzに、FizzBuzzの時だけ判定する数字をファイルに追記する関数を追加してみたいと思います。

number = 15
is_divisible_by_three = number % 3 == 0
is_divisible_by_five = number % 5 == 0

# 判定した数字をファイルに追記する関数
def append_to_file judgment_number
  file = File.open("sample.txt", "a")
  file.write("#{judgment_number}\n")
  file.close
end

# 文のif
if is_divisible_by_three && is_divisible_by_five
  append_to_file number
  statement_result = 'FizzBuzz'
elsif is_divisible_by_three
  statement_result = 'Fizz'
elsif is_divisible_by_five
  statement_result = 'Buzz'
else
  statement_result = 'Other'
end

p statement_result
# FizzBuzz

文のifを使った場合ですと、上記のようになります。

繰り返しstatement_resultに代入しているのを共通化したくなりますね。

ですが、FizzBuzzの時だけappend_to_file numberを呼び出しているのは悩みませんか?

append_to_file numberがなければ、前述のifの式で書いた方法で良いと思います。

append_to_file numberが共通ではないから、これはどうするか悩みますね。

解決法は大層なことではないのですが、ifの式にそのまま書けば良いだけです。

具体的には以下です。

number = 15
is_divisible_by_three = number % 3 == 0
is_divisible_by_five = number % 5 == 0

# 判定した数字をファイルに追記する関数
def append_to_file judgment_number
  file = File.open("sample.txt", "a")
  file.write("#{judgment_number}\n")
  file.close
end

# 式のif
return_value = if is_divisible_by_three && is_divisible_by_five
                 append_to_file number
                 'FizzBuzz'
               elsif is_divisible_by_three
                 'Fizz'
               elsif is_divisible_by_five
                 'Buzz'
               else
                 'Other'
               end

p return_value
# FizzBuzz

Rubyのif 式は、条件が成立した節の最後に評価した式の結果を返すという性質がありましたね。

if 式は、条件が成立した節(あるいは else 節)の最後に評価した式の結果を返します。else 節がなくいずれの条件も成り立たなければ nil を返します。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html

ですので、FizzBuzzの条件分岐の中において、最初にappend_to_file numberが評価されて最後に‘FizzBuzz’がくるので、‘FizzBuzz’を返しているということになります。

上記のようなifの式で共通化ができました。

おわりに

文と式を理解する一つのメリットとして、コードの書き方のレパートリーを増やすことができます。

一例として処理を共通化することができました。

文と式を理解するメリットは他にもあるよということがありましたら、良ければコメントで教えてください。

この記事がなにかのヒントになりましたら、幸いです。

最後まで記事を読んでいただいて、ありがとうございました!!

コメント

タイトルとURLをコピーしました