質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

Q&A

解決済

2回答

2982閲覧

Rubyで『ある年のある月の日数を求めるメソッド』を作成したのですが...

Kei227

総合スコア44

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

0グッド

1クリップ

投稿2015/11/16 11:21

閏年かどうかの判定のために以下の条件を設けて、『ある年のある月の日数を求めるメソッド』をRubyで作成しました。

-閏年の条件-
① その年が4で割り切れること
② ただし、年が100で割り切れて400で割り切れない場合は閏年ではない

lang

1def get_days(year, month) 2 month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 3 if month == 2 4 if year % 4 == 0 5 if (year % 100 == 0) && (year % 400 != 0) 6 days = 28 7 else 8 days = 29 9 end 10 else 11 days = 28 12 end 13 else 14 days = month_days[month - 1] 15 end 16 17 return days 18end 19 20while true do 21 puts "年を入力してください:" 22 year = gets.to_i 23 puts "月を入力してください:" 24 month = gets.to_i 25 26 days = get_days(year, month) 27 puts "#{year}年#{month}月は#{days}日間あります" 28end

メソッドの最後に書いた【return days】は必要ないでしょうか?入れても入れなくても結果は変わらなかったので必要ないかと思ったのですが、模範解答にはこの記述がありましたので気になります。

また、改善点などもございましたら合わせてご教授願います。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

return の有無についての説明はすでに説明がありましたが、
質問文のコード自体についてコメントがあります。

ある年のある月の日数を求めるのを3つの方法で書いてみました。

  1. 質問文のコードを変更したもの
  2. Date#leap? メソッドを使ったもの
  3. Date のイニシャライザを使ったもの

質問文のコードについては次の点を変更しています。

  • month_datas は 定数にして メソッドの外の出して、一度だけ生成するようにした。
  • うるう年の判定をメソッドとして独立させた。
  • while true do は loop do に置き換えた。

ruby

1require 'date' 2 3MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31].freeze 4 5def get_days(year, month) 6 days = MONTH_DAYS[month - 1] 7 days = 29 if month == 2 && Date.leap?(year) 8 days 9end 10 11def leap_year?(year) 12 ans = false 13 if year % 400 == 0 14 ans = true 15 elsif year % 4 == 0 && year % 100 != 0 16 ans = true 17 end 18 ans 19end 20 21def get_days2(year, month) 22 days = MONTH_DAYS[month - 1] 23 days = 29 if month == 2 && leap_year?(year) 24 days 25end 26 27loop do 28 puts '年を入力してください:' 29 year = gets.to_i 30 puts '月を入力してください:' 31 month = gets.to_i 32 33 days = get_days(year, month) 34 days2 = get_days2(year, month) 35 days3 = Date.new(year, month, -1).day 36 puts "#{year}#{month}月は#{days}, #{days2}, #{days3}日間あります" 37end

実行例:

$ ruby 1.rb 年を入力してください: 2000 月を入力してください: 2 2000年2月は29, 29, 29日間あります 年を入力してください: 2004 月を入力してください: 2 2004年2月は29, 29, 29日間あります 年を入力してください: 2100 月を入力してください: 2 2100年2月は28, 28, 28日間あります

↑のコードは rubocop で警告はでません。
(質問文のコードはいくつか警告がでます)

参考情報:

...
Date.new の第3引数に負の数を指定すると、月末からの日付で初期化できます。
-1 を指定すれば月末の日付を取得できます。
...

追記: 2015-11-16 23:30
rubocop の警告の例;
イメージ説明

投稿2015/11/16 13:11

編集2015/11/16 14:36
katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kei227

2015/11/16 13:35

より良いコードへの訂正ありがとうございます。 * while true do は loop do に置き換えた。 こちらの変更は、breakで処理から受け出すためでしょうか?(whileだと永遠に抜けられないので) また、whileとloapはどのように使い分けていけばいいかなどのアドバイスがございまいしたら教えていただきたいです。
Kei227

2015/11/16 14:11

【追記】 Sublime Textに教えていただいたrubocopを適応させようと思い、以下のマニュアル通りに実行したのですが、 ======= Manual: Navigate to the Sublime Text Packages folder (You can find the location of the Packages folder here). Run the git clone command right inside the packages directory: git clone git@github.com:pderichs/sublime_rubocop.git "RuboCop" Restart Sublime Text. ======= エラーが発生してしまいます。 ======= MBP:~ k$ cd ~/Library/Application\ Support/Sublime\ Text\ 3/Packages/ MBP:Packages k$ git clone git@github.com:pderichs/sublime_rubocop.git "RuboCop" Cloning into 'RuboCop'... Warning: Permanently added the RSA host key for IP address '192.30.252.130' to the list of known hosts. Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. ======= 調べてみると下記の記述を見つけたので、 ======= ■原因 git remote add したリポジトリのパスが間違ってる可能性が高い。 ■対策 git remote rmしてパスを確認して、間違っているならaddし直す。 ======= 『git remote rm』を実行して対処しようと試みたのですが、エラーが出てしまいます。 ======= MBP:Packages k$ git remote rm fatal: Not a git repository (or any of the parent directories): .git ======= どのようにすれば無事SublimeでRuboCopを使えるようになりますでしょうか?
katoy

2015/11/16 14:34

loop do でも while true でも break でループから脱出はできます。 回答のほうに追記しましたが、 rubokop ( atom 上で動作させています) で警告がでるので、それを解消させたのです。 subline は使っていないので、わかりません。 rubocop はコマンドラインでもつかえます。(エディタと連動させたほうが便利だけど)
guest

0

ベストアンサー

Rubyのメソッドではreturn文が無い場合、最後に評価された式の値が返されます。そして、Rubyではifは式であり、最後に評価された式の値が返されます。なので、return daysがなくても結果が変わらないのです。

もうちょっと、細かく説明していきます。return daysが無かった場合を考えます。一番最後の式は、if month == 2から始まってそれに対応するendです。つまり、メソッドの返り値としてこの式の値が返されます。では中身を見ると、もし、monthが2の場合はif year % 4 == 0から始まってそれに対応するendが最後の式、2ではない場合はdays = month_days[month - 1]が最後の式です。if year % 4 == 0をみるとさらにifが入れ子になっていて、最終的に全てdays = 【何か】という代入式が最後に評価された式になります。つまり、days = 【何か】を式として評価したときに、返す値がそのまま各ifでも返す値になり、最終的にメソッドが返す値になると言うことです。そして、代入式は単純に代入された値を返します。結局の所、daysに代入された値がメソッドの返り値になっているのです。なので、return daysが無かったとしても、いまのコードではどのif分岐を辿ってもdaysへの代入で終わるので、ちゃんとした値が返ると言うことです。return daysと各所のdays =を削除して、値だけにしても、同じになることが確認できると思います。

では、return daysを消しちゃっていいかというとそうではありません。もし、return daysが無ければ、全てのif分岐について最後に評価される式の値が返り値としたいかを確認する必要があるからです。ちょっとかえただけでうまく値を返さずに、わかりにくいバグのもとになります。たとえば、デバッグ用にdays = 28の後だけputs "#{year} is a leap year!"とかつけたらどうでしょう?閏年の時だけputsの式が最後になって、おかしくなってしまいます。いいコードというのは、こういった変更に強い(全体を変えなくても部分的な変更ができる)コードです。ですので、模範解答はreturn daysをつけて、部分的な変更があっても意味が変わらないようにしているのです。

上を読み返してみると、自分でも何言っているのかわかりませんでした。

Rubyの仕様上、returnが無くてもこのコードは動くけど、説明がちょっと複雑だから、わかりやすいコードになるようにちゃんとreturnを書こうね!

って、覚えておけば大丈夫っす!

投稿2015/11/16 12:17

編集2015/11/16 12:29
raccy

総合スコア21733

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kei227

2015/11/16 12:30

returnをつけることで返り値を明確にし、部分的な変更があってもメソッドの意味を変えないのですね。 『全てのif分岐について最後に評価される式の値が返り値としたいかを【確認する必要がある】からです。』 の【確認する必要がある】というのは何か具体的な動作を指すのでしょうか?
raccy

2015/11/16 12:36 編集

if分岐の一つ一つについて、最後に何の式を評価しているのかを**プログラマー**が目視で【確認する必要がある】ということです。ifが1段階だけであればそれほど難しくないですが、今回のように3段階ぐらいネストしてしまうと結構大変だと思います。それよりは、それぞれでdaysに入れるという明確な処理と、最後にdaysを返すってしたほうが、理解もしやすい=いいコードということなのです。
Kei227

2015/11/16 12:43

理解できました。誰が見ても意図通りに理解される分かりやすいコードを書くことを心がけます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問