こちらのクイズの答えと解説(?)です。
ruby 2.3.0で動作確認しています。
クイズ1
Aの出力結果は何でしょう?
def hoge(options = {})
foo = options.delete(:foo)
puts "foo is #{foo}"
puts "options is #{options}"
end
options = {foo: 'FOO', bar: 'BAR'}
hoge(options)
puts options #=> A
答え
Aの出力結果 : {:bar=>"BAR"}
解説
rubyは参照の値渡しを行いますので、引数を受け取った先(#hoge
)で引数の破壊的な変更を行うと、
メソッドの呼び出しもとに影響があります。
#deelte
は!
はついていませんが破壊的メソッドなので注意です。
クイズ2
A, Bの出力結果は何でしょう?
INIT_STR = 'INIT STR:'
def hoge(num)
temp = INIT_STR
num.times do |n|
temp << " #{n}"
end
temp
end
puts hoge(3) #=> A
puts hoge(3) #=> B
答え
Aの出力結果 : INIT STR: 0 1 2
Bの出力結果 : INIT STR: 0 1 2 0 1 2
解説
rubyは定数を書き換えてもエラーになりません。
<<
メソッドでは値を書き換えてしまうので、このクイズの場合、実行するたびにINIT_STR
が書き代わってしまします。
#freeze
をつけておくと定数の変更はできなくなるので、必ず付けるようにすると良いでしょう。
INIT_STR = 'INIT STR:'.freeze
クイズ3
Aの出力結果は何でしょう?
def hoge(options = {}, foo: 'FOO')
puts options
puts foo
end
hoge(bar: 'bar', foo: 'foo') #=> A
答え
Aの出力結果 : ``hoge': unknown keyword: bar (ArgumentError)`
解説
詳しく追っていないのですが、デフォルト引数とキーワード引数を併用するときは注意。
クイズ4
A〜Hの実行結果は何でしょう?
Array(1) # => A
Array(nil) # => B
Array([]) # => C
Array.new # => D
Array.new(1) # => E
Array.new(nil) # => F
Array.new(nil.to_i) # => G
Array.new([]) # => H
答え
Aの出力結果 : [1]
Bの出力結果 : []
Cの出力結果 : []
Dの出力結果 : []
Eの出力結果 : [nil]
Fの出力結果 : no implicit conversion from nil to integer (TypeError)
Gの出力結果 : []
Hの出力結果 : []
解説
Array
メソッドは引数で受け取った値を値として持つ配列を返します。
Array("test") #=> ["test"]
引数の値はすでに配列の場合はそのまま返します。
Array(["test"]) #=> ["test"]
Array.new
は受け取った第1引数の数だけ、第2引数の値を持つ配列を返します。第2引数のデフォルト値はnilです。
Array.new(3) # => [nil, nil, nil]
ちなみにnil.to_i
は0になります。
クイズ5
Aの実行結果は何でしょう?
class Hoge
def foo
self.bar
end
private
def bar
puts 'bar'
end
end
Hoge.new.foo # => A
答え
private method
bar' called for #Hoge:0x007fe96a07cde8 (NoMethodError)`
解説
rubyのprivateメソッドは「レシーバを指定して実行できない」メソッドなので、たとえself
でも付けることはできません。
初学者が引っかかりやすいので注意。
クイズ6
Aの実行結果は何でしょう?
class Hoge
attr_accessor :foo,
def initialize(foo)
@foo = foo
puts @foo
end
end
Hoge.new('bar') # => A
答え
wrong number of arguments (given 1, expected 0) (ArgumentError)
解説
2行目に余計な,
がついているのでエラーになるのですが、何故かエラー箇所が10行目になります。
なんででしょうね。
クイズ7
A, Bの実行結果は何でしょう?
def hoge
sleep 1 # 重い処理
'hoge'
end
if result1 = hoge
puts result1 # => A
end
puts result2 if result2 = hoge # => B
答え
Aの実行結果 : hoge
Bの実行結果 : undefined local variable or method `result2' for main:Object (NameError)
解説
ifをインラインで書いたときのそうでないときにスコープが若干違うようです。
インラインで書いたときにはifの条件式で新しく定義した変数は他で使えないようです。
詳しい理由をstackoverflowで教えてもらいました(1年越しの追記)。