Ruby勉強会第13回

先日、Ruby勉強会第13回に参加してきました。

一応発表させていただく時間を持たせてもらって、Ruby クイズというタイトルで、多肢選択式の問題を5問ほどといてもらうという企画を行いました。

それで発表資料のアップロードをしようと思っていたら、いつの間にやら誰かがまとめて、Wiki の方に記入していただけたようです。いやはや、ありがとうございます。

ちょっと作業が遅れましたが、発表資料をアップロードしました。
http://jp.rubyist.net/?c=plugin;plugin=attach_download;p=KansaiWorkshop13;file_name=ruby-quiz013.pdf

復習したい方ご利用ください。


PDF が嫌な方のためにテキストで問題と補足的な解説を下記で記載しておきます。

第一問
以下は Ruby の文字列への記述である。正しいものを選べ
(1) Ruby での文字列はマルチスレッド処理を前提とした設計になっており、他のスレッドにより突然変更されることがないよう値が不変の文字列クラスと文字列構築用の文字列クラスがある。
(2) Ruby の文字列では、ヌル文字 (\000 に相当する文字)以外の任意のバイト列を扱える
(3) Ruby の認識するマルチバイトエンコーディングには、EUC, SJIS, JIS, NONE の4種類がある。
(4) Ruby での文字列は任意の長さのバイト列を扱うことができ、日本語文字も特殊なグローバル変数に漢字コードを設定することによって正しく処理可能である。
選択肢
(ア) 1 		(イ) 2		(ウ) 3		(エ) 4

正解は4です。
上記の選択肢は Ruby を利用する人にとってはすべてよく疑問に思われるものです。

解説は 資料の方で十分だと思うのでそちらを参照してください。

第二問

次の出力は?
 p <<EOD % “RubyI love #{%{#{%q{%s}}}}
EOD
(ア) “I love #{%q{Ruby}}\n”
(イ) “I love Ruby\n”
(ウ) 文法エラーで出力されない
(エ) “I love Ruby

この問題は、% が4つ、{} が4つ出てくるというアバンギャルドなコードが私の中で素敵だったので、今回設問として採用しましたっ。

ポイントとしては、<

第3問
問 次のうちパースエラーまたは実行時エラーになるものは?

(1)  "Perl" = "Ruby"
(2)  "Perl".replace "Ruby"
(3) a = “Perl”
    a["Perl"] = "Ruby"
(4) a = "Perl"
    a[/Perl/,0] = "Ruby"
(5) 
class A
  def to_str
    "class A“
  end
end
"" + A.new

選択肢
(ア) 1	(イ) 1,2  (ウ) 1, 5   (エ) 1, 3, 4 (オ) 3, 4

解答

解説
第3問が今回の問題の中で最も難しい問題でした。
この問題以外の全問正解という方は結構いたんじゃないでしょうか?
この問題を悩まず正当できる人はかなりの Ruby マニアですね。

(1) は、ちゃんと文法エラーになる例です。
代入文の左辺にリテラルをとることはできません。

(2) は、ちゃんと今回説明できなかったかもしれないのですが、文字列リテラルというのは Ruby では文字列オブジェクトの生成構文です。文字列リテラルは文法要素上の式にあたり、任意の String オブジェクトとしてのメソッド呼び出しが可能で、破壊的に変更するメソッドも呼び出し可能です。

(3) (4) は、String#sub! メソッドに相当する内容を実行しています。
まぁ、実際上このテクニックを使うことはほとんどなく、99%の人は sub メソッドによって行うでしょうし、そうするべきです。
クイズという形式で知らない人が多そうなことをトピックにしているので取り扱いましたが、おすすめできない記法です。

(5) については知らない人が多そうでしたね。文字列の暗黙の変換についての知識を問う問題でした。

今回はポイントだけ抑えるために文字列への暗黙の変換を定義する to_str メソッドだけを定義しましたが、これは良くない例でしょう。実際には to_str を定義するようなクラスというのは String が持つメソッドはほとんどすべて持っているようなクラスに限定することが望ましいです。

第4問
次の実行に対する正しい出力の組み合わせを選べ。

(1)
a = "dog"
b = a[0,2]
b = "pi"
p a

(2)
a = "dog"
b = a[0,2]
b.replace "pi"
p a

(3)
a = "dog"
a[0,2] = "pi"
p a

選択肢
(ア) 1: "dog"   2:"dog"    3: "dog"
(イ) 1: "dog"   2:"dog"    3: "pig"
(ウ) 1: "dog"   2:"pig"    3: "pig"
(エ) 1: "pig"   2:"pig"    3: "pig"

解答は(イ)の "dog" , "dog" , "pig" です。

self#[index,length] の形式で得られる部分文字列は、元の文字列とは独立した文字列です。すなわち、部分文字列を変更しても元の文字列には影響はありません。

この問題は Ruby の文字列の実装について理解を深めてくれるでしょう。

なお、簡単な解説を行っておくと、(1) のような代入文の場合は新しいオブジェクトが生成され、そのオブジェクトを指すように変数b の指し先(オブジェクトID)が変わるという動作になります。(2) の replace メソッドの場合は、変数b の指し先の内容が "pi" という文字列に変更されます。このとき、ラベルb のオブジェクトIDは同一のものとなります。

代入文と replace メソッドは非破壊的と破壊的という違いがあります。この違いは重要ですので、注意して使い分けるようにしましょう。

第5問
以下の対応関係を適切に結べ

(1) p sprintf("% 6d",2007)
(2) p sprintf("%+6d",2007)
(3) p sprintf("%06d",2007)
(4) p sprintf("%-6d",2007)

(a) "002007"
(b) "  2007"
(c) "2007  "
(d) " +2007“

選択肢
(ア) 1-b , 2-d , 3-c , 4-a
(イ) 1-d , 2-b , 3-a , 3-c
(ウ) 1-b , 2-d , 3-a , 4-c
(エ) 1-b , 2-a , 3-d , 4-c

解答

この問題の解説は発表資料の方で十分に行っていますし、Ruby に限定されないトピックですので、解説しません。sprintf で検索すればよい解説を多く発見できるでしょう。

懇親会で感想を聞いてまわったところ、全般的にはマニアックな問題が中心だったが、とても楽しめたという感想が多く、良かったです。このあたりの難易度の設定がとても難しいですね。比較的簡単な問題も混ぜつつ、全問正解が続出するようでは設問として良くないので、とても難しい問題を用意したりと工夫しました。

みなさんに楽しめてもらえたことが何よりでした。