2013-08-20 55 views
2

我有下面的代碼:ruby​​中的宇宙飛船<=>運算符如何拋出異常?

def sort_descending _objects, field 
    _objects.sort { |b,a| a.send(field) <=> b.send(field) } 
end 

a.send(field)返回Stringb.send(field)返回一個Integer,那麼ArgumentError被拋出。我試圖抓住這個異常是:

def sort_descending _objects, field 
    _objects.sort { |b,a| safe_compare(a,b,field) } 
end 

def safe_compare a, b, field 
    a.send(field) <=> b.send(field) 
rescue 
    a.send(field).to_s <=> b.send(field).to_s 
end 

,但這也會引發ArgumentError。我不知道爲什麼。任何人都可以解釋排序引發的異常行爲嗎?

雖然這種解決方法的工作原理,它看起來醜陋

def sort_ascending _objects, field 
    _objects.sort do |a,b| 
    safe_compare(a,field,b) <=> safe_compare(b,field,a) 
    end 
end 

def safe_compare a, field, b 
    _a,_b = a.send(field), b.send(field) 
    _a.class == _b.class ? _a : _a.to_s 
end 

代碼來重現是here

+0

的原因'ArgumentError'沒有被捕獲在此說明:http://stackoverflow.com/questions/10692860/ruby-ignores-rescue-辯論錯誤 – lurker

+0

重現問題的代碼應該包含在問題中,並且是簡短的摘要,而不是其他地方的鏈接。你要求我們追逐頁面來幫助你。見http://sscce.org/ –

+0

@TheTinMan哦,對不起。我保證會變得更好。儘管我的帳戶年齡稍大,但我只是開始積極使用它。 – Nockenfell

回答

4

有人可以解釋一下嗎?

是的,方法< =>()不會引發異常。請看一下:

def sort_descending _objects, field 
    _objects.sort {|b,a| safe_compare(a,b,field) } 
end 

def safe_compare a, b, field 
    a.send(field) <=> b.send(field) 
rescue 
    puts 'in rescue clause' #Let's trace the flow of execution 
    a.send(field).to_s <=> b.send(field).to_s 
end 

class Dog 
    def greet 
    "hello" 
    end 
end 

class Cat 
    def greet 
    10 
    end 
end 

d = Dog.new 
c = Cat.new 

p d.send("greet") 
p c.send("greet") 

p safe_compare(d, c, "greet") 

--output:-- 
"hello" 
10 
nil 

請注意,在rescue子句中,puts語句沒有輸出。

從紅寶石字符串文檔:

string <=> other_string → -1, 0, +1 or nil 

nil is returned if the two values are incomparable. 

這條線:

a.send(field) <=> b.send(field) 

相當於:

a.send(field).<=>(b.send(field)) 

如果a.send(場)返回一個字符串,然後一個字符串正在調用< =>()方法。 Numeric類還定義了< =>()方法,因此如果a.send(field)返回一個數字,則一個數字將調用< =>()方法。兩個字符串#< =>和數字#< =>如果兩個對象不可比較,則返回nil - 它們不會引發異常。其他類有類似的< =>()方法的定義。

因此,在safe_compare方法內不會引發ArgumentError。但是,nil不是來自排序塊的有效返回值,因此sort()會引發ArgumentError。

你需要做這樣的事情:

def sort_descending _objects, field 
    _objects.sort { |b,a| safe_compare a, b, field } 
end 

def safe_compare a, b, field 
    result = a.send(field) <=> b.send(field) 
    result ||= a.send(field).to_s <=> b.send(field).to_s 
end 
+0

非常感謝您的詳細解釋。它很清楚我的問題是什麼。而你的* safe_compare *比我的*解決方案*解決方案好得多。 – Nockenfell

+0

爲了完整起見,我已將您的解決方案添加到完整的要點https://gist.github.com/iboard/6288415 - thanx了。 – Nockenfell

+0

@Nockenfell,另一個更簡單的方法來做你想做的就是不管:_objects.sort {| b,a | (字段).to_s <=> b.send(field).to_s}' – 7stud