Try Catch問題求救


#1

我在console下面輸入
a = {name: ‘tim’}
然後a[:name]可以取到值
但是如果我用a.try(:name)會是nil

想請問一下如果這種情況,我要怎麼打才能用try取到裡面的值

謝謝各位大大


#2

你…弄…錯…了…唄…因為 try 是用來檢查 object 有無 method / attr,而不是檢查 hash 內是否有該 key 的

我寫一票 demo code 來幫你釐清思緒,看不懂的再說聲
而 try 的 doc 在這
http://apidock.com/rails/v3.2.1/Object/try

# hash 該有的用法
x = {:wer => 123}
x.class #=> Hash
x[:wer] #=> 123
x[:sdf] #=> nil
x.has_key?(:wer) #=> true
x.has_key?(:sdf) #=> false

#檢查是否有該method , 純ruby簡易版
class M
  def temp
    return 123
  end
end
m = M.new
m.class #=> M
m.methods #=> 一大票,裡面包含 :temp
m.methods.include?(:temp) #=> true
m.methods.include?(:wtf) #=> false
m.try(:temp) #=> NoMethodError #因為 try 定義在 rails 內

#Rails版本對照與同義
require 'rails'
m.try(:temp) #=> 123
m.try(:wtf) #=> nil
m && m.methods.include?(:temp) ? m.temp : nil #=> 123
m && m.methods.include?(:wtf) ? m.wtf : nil #=> nil
m && m.methods.include?(:temp) ? m.send(:temp) : nil #=> 123 改用 send 來 call method
m && m.methods.include?(:wtf) ? m.send(:wtf) : nil #=> nil

#寫一個完全一樣的功能出來
class M
  def try2(method_name)
    self.methods.include?(method_name) ? self.send(method_name) : nil
  end
end

m.try2(:temp) #=> 123
m.try2(:wtf) #=> nil

hash 的 key 可以當作 method 來用的全世界大概只有 JavaScript … 其餘大概就這樣而以唄,以上


#3

Hash 用 fetch…


#4

hsh[:key] 其實是呼叫 Hash#[] 這個方法,try 的話也應該是 hsh.try(:[], :key) 不過如果你確定他是 Hash 那他一定有 [] 這個方法,你需要的是用 Hash#fetch 這個方法 hsh.fetch(:key)


#5

嘛… fetch 沒 key 會噴 exception 的哩,所以我還是愛 has_key? + []

不過另外補充,如果依照 try 的原意用 fetch 應該要這樣下就不會有 exception (第二個參數為預設值)

x = {:wer => 123}
x.fetch(:x , nil) #=> nil
x.fetch(:wer , nil) #=> 123

即為所求


#6

我都會自己寫一個 Hash#fetch? 的 extension XDDDDDDDDD

module HashFetchOrNil
  def fetch?(key)
    fetch(key, nil)
  end
end

Hash.send(:include, HashFetchOrNil)

不過 fetch? 這種命名法不是很 match ? pattern (帶問號的方法回傳布林) 所以就自己用的時候記得就好XDDD

或是要自己增加一個 Hash#allow_nilable_fetch 之類的方法,然後讓出來的 instance 的 fetch 可以預設 nil,可是這就太牽涉 meta programming 了而且其實不值得XD