Ruby Gold基礎力確認問題 誤答一覧

問6: ブロック引数と引数の書き方

ブロック引数で{ }を使った書き方をする場合は、ブロックに送る引数に()を省略することは出来ない。 これは、普段コードに見慣れているとなんとなくわかるが、

do..endでブロック引数を書く場合、ブロックに送る引数は()を付けても、付けなくてもよい。

1.upto(5)do |x|
  puts x
end

1.upto 5 do |x|
  puts x
end

1.upto(5){ |x|
   puts x
} 

3つとも機能する。一番上の例は見慣れないけど、ちゃんと実行される。

問8: 可変長引数とキーワード引数

[1,2,3]という標準出力を期待するとき

def hoge(*args)
  p args
end

hoge [1,2,3] # [[1, 2, 3]]
hoge *[1,2,3] # [1, 2, 3]

hogeの引数argsは配列であり、渡された引数を一要素ずつ配列として扱っていく。 よってargsをそのまま出力すれば、配列に入った配列が返ってくる。

一方、実引数の時点で*を付けてやると「配列展開」が行われ、配列の各要素はそれぞれ3つの別個の要素として、argsに渡される。 これにより、3つの別個の要素を配列に格納する。これにより、期待する出力が出せる。

配列展開はメソッド内で行っても良いので、以下のような書き方もできる。

def hoge(*args)
  p *args
end

hoge [1,2,3] # [1, 2, 3]

また、キーワード引数についても調べてみる。

def hoge(x:, y: 2, **params)
  puts params # {:a=>100, :z=>3}
  puts "#{x},#{y},#{params[:z]}" # 1,2,3
end

hoge a:100, x:1, z:3

仮引数のは一番最後に置くことで、残りのキーワード引数をハッシュで受け取ってくれる。 hash_nameなのでhash_name[key]でキーワードを指定して値を取得することが出来る。

問9: キーワード引数

キーワード引数は本来、仮引数にキーワードを指定して使うものだが、任意のキーワードをハッシュ展開の形で受け取ることもできる。

def method(x:, y:, **params)
   p x
   p y
   p params
   p '-----'
end

method(**{x: 100,y: 100,d: 100, r: 700}) # ハッシュにして**で展開
method(:x => 100, :y => 900)             # 指定なしのキーワード引数を省略
method(x:100, y: 200, **{:r => 1000})    # 一部だけハッシュにして展開
method() # key.rb:11:in `<main>': missing keywords: x, y (ArgumentError)
pyons@LAPTOP-SF87NLCB:/mnt/c/Users/broad/OneDrive/products/Ruby認定技術者試験Gold$ ruby key.rb 
"X: 100, Y: 100, params: {:d=>100, :r=>700}"
"X: 100, Y: 900, params: {}"
"X: 100, Y: 200, params: {:r=>1000}"
key.rb:8:in `<main>': missing keywords: x, y (ArgumentError)

paramsのハッシュ展開をやめてみと、key.rb:1: syntax error, unexpected tIDENTIFIEとなる。 ハッシュ展開で引数を引き受けない限り、必ず引数が必要となる。

問13: self

インスタンス化されたクラスのクラス定義内で出てくるselfインスタンスselfであるという点に注意する必要がある。 メソッドが呼ばれると、「一歩右へ、それから上へ」の原則でメソッド探索を始めた後、該当のメソッドに到達すると呼び出しメソッドのレシーバーをsellfにして実行される。

module M 
  puts self.class # Module
  def foo
    self.class 
  end
end

class C 
  include M 
end

puts C.new.foo # C

レシーバーやクラス定義の内側のselfはクラスやモジュール自身となる。 よって、module内の標準出力はModuleとなる。

問18: protected

protectedに設定されたメソッドは、レシーバーを付けても呼び出すことが出来る。ただし、(本体と継承先の)クラス定義内からの呼び出ししか受け付けない。priveteはクラス内部からの実行のみ受け付ける。

class Parent
  def self_call
    self.method1
  end
  protected
  def method1
    'protected method'
  end
end

p Parent.new.self_call # "protected method"
p Parent.new.method1   # key.rb:21:in `<main>': protected method `method1' called for #<Parent:0x007fffba087408> (NoMethodError)


class Child < Parent
  def call_from_childe
    self.method1
  end
end

p Child.new.call_from_childe # "protected method"

問22: 正規表現と$記号

%r|(http://www(\.)(.*)/)| =~ "http://www.abc.com/"

 puts $0 # upto.rb (プログラム名)
 puts $1 # (http://www(\.)(.*)/)の部分: http://www.abc.com/
 puts $2 # (\.)の部分: .
 puts $3 # (.*)の部分: abc.com

$nはn番目の括弧に対応する文字列を指しており、括弧が入れ子になっていても、正規表現マッチに対応する部分を取得できる。

問27: Socketライブラリにある全クラス

  • UDPはソケットがソケットとサーバーを兼ねる。
  • TCPにはソケットとサーバーが別クラスで用意されている。
  • BasicScoektクラスはインターネット関連のソケットIPSocketUNIXのプロセス間通信のサーバー側を担うUNIXSocketとそのサーバー側となるSocketクラスが継承される抽象クラスで、サーバー側のクラスもここから継承されている。よってBasicServerクラスは存在しない。

問29: 標準添付ライブラリ全般

  • StringIOはIOと同じインターフェースを持つ => Yes. そのためのStringIO. ただし、直接の継承関係はなし。
  • FloatとRationalの演算結果はFloat => Yes. その分、精度が下がってしまいそうだが、そういう仕様なので。
  • rdocは*において番号付きリストを作る。 => No. # 1. List 1 # 2. List 2で作る。数字の後にコンマが必要。
  • Treadのstart, fork, runはいずれも新しいスレッドを作る。 => No, new, start, forkが正解。runwakeupとともに再開用。
  • DateTimeに1足すと翌日になる。=> Yes. 因みにDataもなる。

問30: open-uriクラス

もはや教科書で扱われてすらいなかった。なんで載せたんだよ...

library open-uri (Ruby 2.6.0 リファレンスマニュアル)

Karnel#openの再定義を行うようだ。普段はIOFileのクラスメソッドとして使われていて、単独で使うことはないが、このモジュールが可能にしている。