ブロックつきメソッドやyield文の用途について

このQ&Aのポイント
  • ブロックつきメソッドやyield文の用途についての疑問が出てきました。自作メソッドにブロックを引数として与える利点や、処理の流れがわかりやすい場合などについて教えてください。
  • ブロックつきメソッドやyield文は、主に大規模なプログラムや複数の人で作業する場合に便利です。しかし、テキストファイルの編集や比較、結合などの目的で100〜200行程度の規模のプログラムを作成する場合には、利点が少ないかもしれません。
  • 具体例を交えて、ブロックつきメソッドやyield文の用途について教えてください。どのような場面で活用することができるのか、具体的なイメージを持つことができると助かります。
回答を見る
  • ベストアンサー

ブロックつきメソッドやyield文の用途について

こんにちは。 漠然とした質問なのですがご教示ください。 プログラミング初心者で、 現在、「楽しいRuby」と「プログラミング言語Ruby」を読みながら 勉強をしています。 そのなかで「ブロックつきメソッド」や「yield文」の用途についての 疑問が出てきました。 疑問というのは、  「わざわざ、『ブロックを引数として自作メソッドに与える』  ことの利点ってなに?」 ..です。 私としては、  自作メソッドを呼び出した後、その中のyield文で  再度メソッドの外(自作メソッドの呼び出し元)に制御を戻すんだったら、  自作メソッドの中にブロック処理の内容を書いておくか、  または、最初から自作メソッドを呼ばずにブロック処理をするほうが、  処理の流れがわかりやすくてよいのでは??? ..と感じています。 大規模なプログラムを複数の人で作るような場合にはこのようなしくみが あったほうが便利.. ということなんでしょうか? ちなみに私は主に テキストファイルの編集や比較、結合..などの目的で Rubyプログラムを作っていて、規模はせいぜい100~200行くらいです。 他のRubyプログラムとの連携もありません。 「そんな使い方なら、利点はないよ」というご回答でも構いません。 具体例などと併せてご教示ください。 よろしくお願いいたします。

  • emu85
  • お礼率100% (5/5)
  • Ruby
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

> 「わざわざ、『ブロックを引数として自作メソッドに与える』 > ことの利点ってなに?」 自作メソッドの場合、ブロックを引数として自作メソッドに与えることの利点はない、といって良いかと思います。 そもそも、ブロックを引数を使用することの意味(利点)についてですが、私は以下のように考えています。 ある共通(に使用される)メソッドを外部に提供する場合、そのメソッド呼び出し時、呼び出し側の都合により、 呼び出し側で決めた特殊な処理をそのメソッドで実行してほしい場合に、ブロック引数を使用することにより それが最も低コストで実現可能となる。 例えば、共通なメソッドとしてソートについて考えて見ましょう。 ソートとはある約束に従って、データを並べ替えることです。 ある約束とは、昇順に並べるか、降順に並べるか等の並べ方に関する規則です。 この昇順、降順等の並べ方に関する規則をどのようにして実装するかということですが、 通常、以下の2通りの方法があります。 1)並べ方の規則をある引数の具体的な値で指定させる。 例えば、並び順(1:昇順 2:降順)を引数で指定する方法です。 2)並べ方の規則を呼び出し側に記述させる。 これが、ブロックを引数として指定するやり方で、 昇順でソートしたい場合、そのようにブロック内に記述し、 降順でソートしたい場合、そのようにブロック内に記述します。 では、上記のどちらがよい方法かということですが、各々の長所、短所は以下のようになります。 1)の方法について(引数でソート順を指定する方法) 長所: パラメータの指定がわかり易いので、初心者でも簡単に利用可能。 短所: ソート時の並べ方が、あらかじめ決まっているので、別の並べ方が必要になった場合は、 ソートメソッド自体も変更が必要になる。 例えば、昇順、降順のほかに以下のような並べ方が必要になったとします。 「奇数を前半にならべ、偶数を後半にならべる。奇数については昇順にならべ、偶数については 降順にならべる」 これを実装するためには、引数に「3:特殊ソート」を追加し、更にソートメソッド自体も 修正する必要があります。 2)の方法について(ブロックを引数で指定する方法) 長所: 上記の特殊ソートのようなソートが必要になった場合でも、ソートメソッドは一切変更の必要はない。 呼び出し側で、ブロック引数内にその規則を記述すれば、実現可能となる。 短所: ブロック引数の使い方が、初心者にはハードルが高いので、バグを誘発しやすい。 上記を踏まえて、ブロックを引数としてソートを行なう場合、どのくらい自由自在にソートが可能かを以下の ソースで確認して下さい。 -------------------------------------------- datas = [ 10,13,15,16,5,6,80,81,50,51,100,120] # そのまま表示 p "そのまま表示" p datas # 昇順ソート(ブロック指定無しのソート) result = datas.sort p "昇順" p result # 降順ソート result = datas.sort{|x,y| y<=>x} p "降順" p result # 特殊なソート # 奇数を前半に、偶数を後半に並べる。 # 奇数は昇順に並べる。 # 偶数は降順に並べる。 result = datas.sort{|x,y| if x%2 == 0 # xが偶数の場合 if y%2 == 0 # yが偶数の場合、降順ソート y<=>x else # yが奇数の場合、yを前半へ 1 end else # xが奇数の場合 if y%2 == 0 # yが偶数の場合、yを後半へ -1 else # yが奇数の場合、昇順ソート x<=>y end end } p "特赦なソート" p result # 1人は[名前,性別,年齢]の配列(性別は1:男、2:女) people = [["taro",1,20],["hanako",2,20],["jiro",1,18],["aiko",2,22],["saburo",1,50],["hanae",2,55]] # そのまま表示 p "そのまま表示" p people # 名前順(ブロック指定無しのソート) p "名前順" result = people.sort p result # 性別、年齢順 result = people.sort{|x,y| if x[1] != y[1] x[1] <=> y[1] else x[2] <=> y[2] end } p "性別、年齢順" p result -------------------------------------------- 実行結果は以下のようになります。 -------------------------------------------- "そのまま表示" [10, 13, 15, 16, 5, 6, 80, 81, 50, 51, 100, 120] "昇順" [5, 6, 10, 13, 15, 16, 50, 51, 80, 81, 100, 120] "降順" [120, 100, 81, 80, 51, 50, 16, 15, 13, 10, 6, 5] "特赦なソート" [5, 13, 15, 51, 81, 120, 100, 80, 50, 16, 10, 6] "そのまま表示" [["taro", 1, 20], ["hanako", 2, 20], ["jiro", 1, 18], ["aiko", 2, 22], ["saburo", 1, 50], ["hanae", 2, 55]] "名前順" [["aiko", 2, 22], ["hanae", 2, 55], ["hanako", 2, 20], ["jiro", 1, 18], ["saburo", 1, 50], ["taro", 1, 20]] "性別、年齢順" [["jiro", 1, 18], ["taro", 1, 20], ["saburo", 1, 50], ["hanako", 2, 20], ["aiko", 2, 22], ["hanae", 2, 55]] -------------------------------------------- 結論としては、 個人環境で開発を行なう場合は、ブロックを引数とするメソッドは作成する必要はない。 理由は、メソッドに対する要件があらかじめ決まっているので、開発後にもし要件が追加に なっても、その時点で対応すればよい。 但し、rubyで標準で提供されているメソッドでブロック引数をとるものについては(例えばsortメソッド) そのブロック引数の記述の仕方を理解しておく必要がある。 となります。

emu85
質問者

お礼

tatsu99 さん たいへん丁寧なご回答をありがとうございました。 よく理解できました。 仕様変更等への対応時の、コストを下げる方法の一つ..ということなんですね。 共通処理の部分(メソッド)と、個別処理(個別指定)の部分(ブロック)との 切り分けが難しそうですが、経験を積めば分けられるようになるんでしょうか..。 将来、もっと多様なプログラムを作る必要が出てきたときのために、 また、他のかたが書いた ブロックつきメソッドがついたコードを理解するためにも、 使い方を腹に落としてこうと思います。 ありがとうございました!

その他の回答 (1)

回答No.1

>自作メソッドの中にブロック処理の内容を書いておくか、 >または、最初から自作メソッドを呼ばずにブロック処理をするほうが、 >処理の流れがわかりやすくてよいのでは??? そう思うならそうやればいいと思いますが、 一応言っておくとブロックつきメソッドは「どういう処理のブロックが渡されるか分からない」ものなので、 「メソッドの中に」なんて書けません。だから、ブロックを渡すほうが「処理の流れがわかりやすくてよい」んです。 大規模とかは無関係です。 [1,2,3].map!{|i| i ** 2} [1,2,3].map!{|i| i.to_s } このどちらも実現できる処理をmap!メソッドの中に分かりやすく書けますか? >ちなみに私は主に テキストファイルの編集や比較、結合..などの目的で >Rubyプログラムを作っていて、規模はせいぜい100~200行くらいです。 確かにそういう限定的なことにしか使わないなら疑問に思うのも仕方ないでしょうね。 必要性が分からないなら無理して使う必要はありません。 自分で必要だと思うときがあったら使えばいいんだし無ければ無いでそれだけの話です。

emu85
質問者

お礼

play_with_you さん ご回答をありがとうございました。 > 一応言っておくとブロックつきメソッドは「どういう処理のブロックが渡されるか分からない」ものなので、 > .. そもそも、この↑前提条件を理解していなかったためにでた疑問なんですね。 「ブロックの内容がわからない」、 「メソッドに渡すブロックの内容が変更・追加になる可能性がある」 ..というコトを考えると、用途は理解できました。 おっしゃるとおり、 「必要性が分からないなら無理して使う必要はない」 のですが、今は勉強中で、 「『そういうやりかたもある』ということからまずは知っておきたい」 「他の人が書いたコードにブロックつきメソッドが含めれていても理解できるようにしておきたい」 ..という背景があり、質問をしました次第です。 以上です。

関連するQ&A

  • 後処理を保証するブロック付きメソッドの例について。

    後処理を保証するブロック付きメソッドの例について。 後処理を保証するブロック付きメソッドの例として、以下のプログラムがありました。 def omit_brock1 if defined? yield puts "brock exist" else 以下略 2行目のyieldについて質問です。 yieldってはじめからRubyにあったはずです。これをdefined?してもかならずtrueが返るのではないでしょうか?とするとif文使うのも無駄だと思うのですが、どうなんでしょう? よろしくお願いします。

    • ベストアンサー
    • Ruby
  • Ruby 自作メソッドのブロック付きメソッドについ

    いつも、ご教授ありがとうございます。 Ruby でメソッドを自作してそのメソッドにブロックを持たせる場合 ブロック内で返り値を返すためにはどうしたらいいのでしょうか? たとえば以下のような自作メソッドがあるとすると def blocktest(str) if (block_given?) yield str else print "メソッドにブロックが与えられていない"; end end begin #自作したメソッドにブロックを与えた場合 res = blocktest("ブロック付きメソッドのテスト") {|value| print value; print "<br/>" print "メソッドに与えられた引数をprintしています" return "ブロックで返り値" } print res; print "<hr />" #ブロックを与えない場合 blocktest("ブロック付きメソッドのテスト"); rescue => ex print ex.message end 上記のようにブロック内で返り値 を指定して変数resのその返り値を返したい場合 どうしたらいいのでしょうか? 一応、ブロック内でreturnで値を与えてはいますが、例外が発生します。 よろしくお願いしまう。

    • ベストアンサー
    • Ruby
  • Rubyのtimesメソッドから抜けたい

    Rubyの初心者です。 timesメソッドの中にif文を入れて,もし条件を満たしていれば timesメソッドから抜けたいのですが,どうすればいいのでしょうか。 if文の中でbreakしてもtimesメソッドからは抜けられなかったので質問しました。 どうかよろしくお願いします。

  • return文でもメソッドが止まらない?

    いつもお世話になっております。 深さ優先探索をスタックを使わずにJavaで実装したメソッドを書いたのですが なぜかメソッドを終わらせるreturn文まで到達しているようなのに (return直前にメッセージを表示させて到達していることを確認しました) それ以降も動き続けしかも挙動がめちゃくちゃになるという現象に悩まされています。 (かなり長くなってしまっているので実際のプログラムを記載するのは止めます) returnしたら必ずメソッドは処理を終えるものではないのでしょうか? 思い当たることとしたら、再帰呼び出しを使っているので一つメソッドの処理を終わらせても それを呼び出した側にまた処理が戻っているのかも?ぐらいとしか検討がつきません。 せめてreturnが機能しないことに再帰呼び出しが関係あるのかないのかを知りたいです。 完全にお手上げ状態なのでなにか対処法を知っている方、ぜひともよろしくお願いします。

    • ベストアンサー
    • Java
  • 【ruby】二つのブロック付きメソッドをif文で使い分けたい

    二つのブロック付きメソッドhogeとpiyoがあるとします。 ブロックの中に記述するプログラムは同じだが、hogeを使うか、piyoを使うかは条件により制御したいです。 このような場合、どのように書いたら簡素になるでしょうか? sw=true if sw then  hoge() do |x|   puts x  done else  piyo() do |x|   puts x  done end 上記例では冗長の思うのですが、ご指導のほど宜しくお願いいたします。

    • ベストアンサー
    • Ruby
  • ブロック1 Ruby認定試験対策問題

    Ruby認定試験対策問題をやっていたら分からないところがあったので、 教えてください。 2.9-1.ブロック ■問題 testメソッドに渡されたブロックのselfは次のうちどれか? class Foo def test (1..3).each{|i| yield(i)} end end foo = Foo.new foo.test{|i| i } ■回答 トップレベル ■解説 ブロックはメソッドの呼出し先のselfを継承します ■疑問 ・testメソッドに渡されたブロックとは、(1..3)のことを指すのでしょうか。 ・メソッドの呼出し先とは、foo.test{|i| i }のことを意味しているのでしょうか。 ・呼出し先のselfとは、fooかFooのことでしょうか? ・「selfはメソッド内で実行されるとそのメソッドを実行しているオブジェクトを参照することが出来ます」 と別のサイトに記載されていたのですが、「トップレベルのselfとはObjectクラスのメソッドを実行している」、という意味になるのでしょうか。 それがこの問題のどこに関連しているのでしょうか。

    • ベストアンサー
    • Ruby
  • 繰り返し文の利点について

    プログラミングにおいて繰り返し文を使うことは多いと思います。その利点とは同じ処理を何回も書かなくて良いという点だけでしょうか? for文while文、それぞれについて上記以外の利点があれば教えてください。

  • Ruby 文法 ブロックの中で メソッドを呼ぶ

    class Hoge def val 'aaa' end def piyo yield end end h=Hoge.new h.piyo do p h.val #<ーここの話 end 上の様に書く時、ブロックの中で、そのクラスのメソッドを呼ぶ時、上の例だと h.val と書いてますが、これself.valなどと書きたいのですがERRになってしまいます。 h.と書くのがとても嫌なのですが、なにか良い書き方あるのでしょうか?

    • ベストアンサー
    • Ruby
  • メソッドの処理文の種類

    Javaのメソッドの処理は{}の中に書いて、一文ごと文末に「;」を付けます。セミコロン~セミコロンが処理文の単位で、許されたプログラミング規則に従って処理文を書きます。その処理文の種類を網羅したホームページをご存知でしたら教えてください。日本語が良いです。そのURLを提示してくれると幸いです。 私は11個だけ知っています。それを下に並べると、 (1)他メソッドの呼び出し:System.out.println("");setName("佐藤");getName(); (2)ローカル変数の宣言:int a;String a;Program java; (3)代入:a=0;a=b;a=a+3;a=5+3*3/3%1-2;a=true^true&true&&false;a=(Apple)b; (4)インクリメントとデクリメント:a++;++a;a--; (5)オブジェクトの生成:new DefaultConstractor();new Dog("ハチ公"); (6)条件分岐・判断:if(true){・・・;}else{・・・;} switch case (7)繰り返し・反復:while(true){・・・;} for(Object o:list){・・・;} (8)値を返す・メソッド終了宣言:return a;return "佐藤";return 1+1; (9)例外処理:try{・・・;}catch{・・・;}finally{・・・;} (10)アサーション:assert true; (11)インナークラス:interface InnerI{} enum InnerE{} 12、13と他にもある気がして、それを全て網羅して箇条書きなっているマニュアルがあれば分かり易いと思い、質問しています。 何か処理を書いてコンパイルが通るとき、それは上の(1)~(11)に当てはまるからです。1+1;と書いてもエラーになって、「文の左に代入する変数の指定が抜けています」といったメッセージが出ます。単に1+1だけを計算して代入を省くような処理は上の(1)~(11)に無いのです。 英語ホームページなら有って日本語だと無いとなると、日本のITの脆弱性を感じます。アメリカやイギリスのIT輸入に依存しているような気がして、少し残念です。国産の誇れるITを世界に発信したいなー。

    • ベストアンサー
    • Java
  • どのクラスのメソッドか、をどう見極めるか。

    どのクラスのメソッドか、をどう見極めるか。 Java初心者です(教科書で学んで、実践はこれからというレベル)。 参考書やネット上の資料等に掲載されているコードを見ていますと、 import文(10文くらい)で沢山のパッケージをimportしているようなクラスを しばしば目にしますが、このようなクラス内で使われている沢山のメソッドは、 それぞれ、どこかのクラスに属しているメソッドであるかと思います。 これらのメソッドについて、その仕様を知りたいと感じた場合、 それらがそれぞれ、どのクラスに属するのかを突き止める必要があるかと思いますが、 その突き止め方について、どなたか教えて下さい。 (一般的に普及している方法で結構です。) 例えば、知りたいと感じたメソッド名をネット検索し、 そのメソッドが「Javaの組み込みクラス」のメソッドである場合には、 ネット検索でヒットするでしょうから、その検索結果を受けて、 そのヒットしたクラスと、import文の内容とを比較し、 ネット検索でヒットしたクラスが、そのメソッドの格納主であると確信できれば、 それをもとに、そのメソッドの仕様を知ることができますよね。 (自作・他作のメソッドと、名前がバッティングしているかもしれないことを考慮すると、 やや頭が痛くなる問題になりませんか?) ネット検索で辿る方法が、まず頭に浮かびましたが、 これよりも効率的な方法がもし何かありましたら、教えて下さい。 ただ、一方で、 仕様を知りたいと思っているメソッドが、 「Javaの組み込みクラス」のメソッドではなく、 自作(もしくは、他作)のメソッドであった場合、 検索してもヒットはしませんから、その場合には、 import文にある自作もしくは他作のパッケージをしらみつぶしで探していくことになるのでしょうか? 当然、そのメソッドは、同一パッケージ内にあるクラスのpublicメソッドである可能性もありますから、 同一パッケージ内のクラスの中も、しらみつぶしに探していくことになりますよね? 各メソッドがコメントで「○○クラスのメソッド」というように注意書きされてあれば、 このような苦労はないのでしょうが、ネット上のソースを見る限りでは、 そんな親切なコメントはまず期待できないように思います。 以上、まとまりのない質問ではありますが、アドバイスを宜しくお願い致します。 自分のこの疑問が見当違いの疑問でしたら、その時は、ズバリそれを指摘して下さい。

    • ベストアンサー
    • Java

専門家に質問してみよう