Rubyのシンタックスを息を吸うように書くために、少しでも理解が怪しいシンタックスを繰り返したくために書きます。
シンボル編とハッシュ編があるので、基礎がないならこちらも見たほうがいいです。
前提知識
- ハッシュの
key
は、同じデータ型にする必要はない。混乱の原因なので基本は揃えたほうがいい - ただ、
value
は異なるデータ型が入る可能性がある
メソッドのキーワード引数とハッシュ
例えば、以下のようなメソッドがあったとしよう。
Harder かつ Better かつ Faster かつ Stronger であれば以下URLにある曲がリリースできるdaftpunk
メソッドがあったとしよう。
def daftpunk(hard, good, fast, strong)
if hard && good && fast && strong
puts 'release'
else
puts 'not release'
end
end
daftpunk(true,true,true,true)
=> release
メソッドの引数の中身を見れば、どんな意図のメソッドかがわかるけど、以下のメソッドの呼び出しだけ見たら、よくわからないかと思います。
daftpunk(true,true,true,false)
=> not release
そんな時に使うのがキーワード引数というやつです。
引数がtrue
,false
だけの時よりも、だいぶ可読性がいいのではないでしょうか?
キーワード引数を持つメソッドを呼び出す場合は、ハッシュを作成した時と同じくシンボルkey: value
の形式で引数を指定します。
def daftpunk(harder: true, better: true, faster: true, stronger: true)
if harder && better && faster && stronger
puts 'release'
else
puts 'not release'
end
end
daftpunk(harder: true, better: true, faster: true, stronger: true)
=> release
# デフォルト引数は省略可能
daftpunk
=> release
# デフォルト引数は順番を入れ替えることも可能
daftpunk(better: true, faster: true, stronger: true, harder: false)
=> not release
# 未定義なキーワード引数を指定した場合はエラーになります
daftpunk(one_more_time: true)
=> 'daftpunk': unknown keyword: one_more_time (ArgumentError)
デフォルト引数の値がない場合、メソッド呼び出す際に値を明示しないとエラーになります。
def daftpunk(harder: true, better: true, faster: true, stronger:)
if harder && better && faster && stronger
puts 'release'
else
puts 'not release'
end
end
daftpunk(harder: true, better: true, faster: true, stronger: true)
=> release
daftpunk(harder: true, better: true, faster: true)
=> 'daftpunk': missing keyword: stronger (ArgumentError)
メソッドを呼び出す側の引数は、キーワード引数に一致するハッシュを変数に格納して、引数として渡すこともできます。
params = { harder: true, better: true, faster: true, stronger:true }
def daftpunk(harder: true, better: true, faster: true, stronger:true)
if harder && better && faster && stronger
puts 'release'
else
puts 'not release'
end
end
daftpunk(params)
=> release
ハッシュでよく使うメソッド
基本的に使うハッシュは以下。
languages = { ruby: 'rails', php: 'laravel', python: 'django', }
問題1
Hash_Sampleのキーだけを配列で返してください。
正解1
languages = { ruby: 'rails', php: 'laravel', python: 'django', }
p languages.keys
=> [:ruby, :php, :python]
問題2
Hash_Sampleのキーだけを配列で返してください。
正解2
languages = { ruby: 'rails', php: 'laravel', python: 'django', }
p languages.values
=> ["rails", "laravel", "django"]
問題3
特定のキーを持っているかどうか。戻り値が TRUE
/ FALSE
なメソッドを書いてください。
エイリアスメソッド合わせて4つあります。
正解3
languages = { ruby: 'rails', php: 'laravel', python: 'django', }
p languages.has_key?(:ruby)
p languages.key?(:php)
p languages.include?(:python)
p languages.member?(:javascript)
=> true
=> true
=> true
=> false
問題4
ハッシュ(変数languages
)の中でハッシュ(変数others
)を展開させてください。
展開させるハッシュは以下
others = { javascript: 'react', java: 'struts' }
正解4
others = { javascript: 'react', java: 'struts' }
languages = { ruby: 'rails', php: 'laravel', python: 'django', **others }
p languages
=> {:ruby=>"rails", :php=>"laravel", :python=>"django", :javascript=>"react", :java=>"struts"}
問題5
擬似キーワード引数
others = { javascript: 'react', java: 'struts' }
正解5
others = { javascript: 'react', java: 'struts' }
languages = { ruby: 'rails', php: 'laravel', python: 'django', **others }
p languages
=> {:ruby=>"rails", :php=>"laravel", :python=>"django", :javascript=>"react", :java=>"struts"}
問題6
ハンバーガーの注文系のメソッドorder_hamburger
メソッドの引数に、
店内で食べるか(For_Here
)、外で食べるか(To_Go
)を指定して、
それ以外は、擬似キーワード引数にして、トマトやチーズのトッピングが必要か不要かをメソッド呼び出しで指定できるようにしてください。
擬似キーワード引数の参考 (プロを目指す人のためのRuby入門_163p)
return 例
"For_Here"
"with ONION"
"with TOMATO"
"with CHEESE"
正解6
def order_hamburger( where, toppings={} )
p "#{where}"
p 'with ONION' if toppings.key?(:onion)
p 'with TOMATO' if toppings.key?(:tomato)
p 'with CHEESE' if toppings.key?(:cheese)
end
order_hamburger( 'For_Here', onion: true, tomato: true, cheese: true, )
キーワード引数を使う場合と比較すると、存在しないkey
を指定するとエラーが発生するが、類似キーワード引数は、ハッシュなので、どれだけ渡してもエラーが起こりません。
ただ、お仕事での実装は、普通のキーワード引数を使った方がよさそうです。
問題7
キーワード引数に定義されていないキーワードを渡すとエラーになります。
def order_hamburger( where, onion: true, tomato: true )
p "eat at #{where}"
end
order_hamburger( 'For_Here', onion: true, tomato: true, cheese: true, )
=> 'order_hamburger': unknown keyword: cheese (ArgumentError)
これが、どんなキーワードでも受け入れてくれるように書いてください。キーワード(cheese
)を受け入れてください。
return 例
"eat at For_Here {:onion=>true, :tomato=>true, :cheese=>true}"
正解7
def order_hamburger( where, **toppings )
p "eat at #{where} #{toppings}"
end
order_hamburger( 'For_Here', onion: true, tomato: true, cheese: true, )
ハッシュから配列へ変換、配列からハッシュ変換
Hashオブジェクトに対して、to_a
メソッドで配列に変換できます。その際、key
とvalue
の組み合わせが1つの配列になり、その配列が複数の要素としてあり、それをさらに配列としてくくっている多次元な配列になります。
languages = { ruby: 'rails', php: 'laravel', python: 'django', }
p languages.to_a
=> [[:ruby, "rails"], [:php, "laravel"], [:python, "django"]]
逆に、Arrayオブジェクトに対して、to_h
メソッドで配列をハッシュに変換できます。
languages = { ruby: 'rails', php: 'laravel', python: 'django', }
p languages.to_a
=> [[:ruby, "rails"], [:php, "laravel"], [:python, "django"]]
p languages.to_h
=> {:ruby=>"rails", :php=>"laravel", :python=>"django"}
to_h
メソッドで配列をハッシュに変換できますが、key
とvalue
の組み合わせが1つの配列になっていて、その配列が複数の要素としてなどの形式が揃っていないとエラーになります。
langs = ['ruby', 'rails', 'php', 'laravel', 'python', 'django']
p langs.to_h
=> 'to_h': wrong element type String at 0 (expected array) (TypeError)
to_h
メソッドで変換できても、key
が重複した場合は、最後の要素がハッシュの要素になります。key
重複はない方が望ましいです。
langs = [[:ruby, "rails"], [:php, "laravel"], [:python, "django"], [:ruby, "ruby on rails"]]
p langs.to_h
=> {:ruby=>"ruby on rails", :php=>"laravel", :python=>"django"}
# [:ruby, "rails"] の要素が亡くなっていますね
ハッシュの値
ハッシュに、存在しないkey
を指定してもnil
が返ります。
hash = {}
p hash[:test] # => nil
nil
、以外の値を返したい場合は、Hash.new()
の引数に初期値を設定すればできます。
languages = Hash.new('something')
p languages[:ruby] # => "something"
p languages[:php] # => "something"
p languages[:python] # => "something"
p languages[:ruby].object_id # => 70138707695000
p languages[:php].object_id # => 70138707695000
p languages[:python].object_id # => 70138707695000
ただし、注意が必要なのは、上を見てもわかる通り、何回呼び出しても同じ初期値が返ります。なので、初期値に対して、破壊的な変更をすると、呼び出してるやつ全部に影響があります。
その問題を解決する方法としては、ブロック引数として初期値を設定すると、ここの要素はいミュータブルなオブジェクトになります。
languages = Hash.new { 'something' }
p languages[:ruby] # => "something"
p languages[:php] # => "something"
p languages[:python] # => "something"
p languages[:ruby].object_id # => 70174736763180
p languages[:php].object_id # => 70174736762900
p languages[:python].object_id # => 70174736763180
シンボルを作成する方法
エラーになるシンボルの作成方法
こんな場合はエラーになります。
- 数字で始まる
- ハイフンがある
- スペースがある
p :123 # => syntax error
p :ruby-on-rails # => syntax error
p :ruby on rails # => syntax error
上記も、シングルクオートで囲むとエラーになりません。シンボルとして認識されます。
p :'123'
p :'ruby-on-rails'
p :'ruby on rails'
%記法でシンボルを複数宣言
p %i(ruby php python)
=> [:ruby, :php, :python]