2011-05-23 37 views
3

想象一下下面的代碼:有沒有比使用自定義的case語句更有用的方法來在Ruby中編寫它?

class SimpleLetter 
    def values 
    ("a" .. "z").to_a 
    end 

    def ===(other) 
    values.include?(other) 
    end 
end 

class Vowel < SimpleLetter 
    def values 
    ["a","e","i","o","u"] 
    end 
end 

class Consonant < SimpleLetter 
    def values 
    super - Vowel.new.values 
    end 
end 

objects = ("a" .. "f").to_a + (1 .. 5).to_a 

objects.each do |letter| 
    case letter 
    when Vowel.new 
     puts "#{letter} it's a vowel" 
    when Consonant.new 
     puts "#{letter} it's a consonant" 
    else 
     puts "#{letter} it's something else" 
    end 
end 

我可以選擇任何其他類,而不是,我只是用它們作爲一個例子。我非常喜歡Scala的match和提取器,我認爲這可能是在Ruby中編寫相同的東西的一種很好的方式。有沒有更好的方式來寫上述,而不必實例化新的對象,所以我可以調用他們的===方法?

只是爲了避免不必要的崗位,是的,我知道我能做到這一點:

case letter 
    when ["a","e","i","o","u"].include?(letter) 
    # ... 
end 

回答

3

你可以使用類方法而不是實例方法:

class SimpleLetter 
    def self.values 
     ("a" .. "z").to_a 
    end 

    def self.===(other) 
     values.include?(other) 
    end 
end 

class Vowel < SimpleLetter 
    def self.values 
     ["a","e","i","o","u"] 
    end 
end 

class Consonant < SimpleLetter 
    def self.values 
     super - Vowel.values 
    end 
end 

objects = ("a" .. "f").to_a + (1 .. 5).to_a 

objects.each do |letter| 

    case letter 
     when Vowel 
      puts "#{letter} it's a vowel" 
     when Consonant 
      puts "#{letter} it's a consonant" 
     else 
      puts "#{letter} it's something else" 
    end 

end 
+0

使用類方法看起來比我更好的變種很多。我不知道我們可以定義'==='來處理類作用域。 – Geo 2011-05-23 20:04:43

5

你不需要上課那些角色。將它們設置爲數組,並在case語句中使用splat運算符。

SimpleLetter = ("a" .. "z").to_a 
Vowel  = %w[a e i o u] 
Consonant = SimpleLetter - Vowel 

(("a" .. "f").to_a + (1 .. 5).to_a).each do |letter| 
    case letter 
    when *Vowel 
     puts "#{letter} it's a vowel" 
    when *Consonant 
     puts "#{letter} it's a consonant" 
    else 
     puts "#{letter} it's something else" 
    end 
end 
4

===作品上的塊,太:

Letters = ('a'..'z').to_a 
Vowels = ['a','e','i','o','u'] 
Consonants = Letters - Vowels 

Vowel = lambda { |x| Vowels.include? x } 
Consonant = lambda { |x| Consonants.include? x } 

objects = ("a" .. "f").to_a + (1 .. 5).to_a 

objects.each do |object| 
    case object 
    when Vowel 
     puts "#{object} is a vowel." 
    when Consonant 
     puts "#{object} is a consonant." 
    else 
     puts "#{object} is an object." 
    end 
end 
+0

可以使用任何具有'.call'方法的對象嗎? – Geo 2011-05-23 20:10:41

+0

實際上,規則是任何具有'。==='的對象都與'case'語句兼容。 – Tom 2011-05-23 20:12:02

+0

在Ruby 1.8中無法使用 – 2011-05-23 20:44:48

1

你已經有幾個很好的答案(如澤的),所以我包括一個玩票一個沒有case聲明:

SIMPLE_LETTER = [*"a" .. "z"] 
VOWEL  = %w[a e i o u] 
CONSONANT = SIMPLE_LETTER - VOWEL 

[*?a..?f,*1..5].each do |letter| 
    letter_class = %w(vowel consonant).select { |c| Object.const_get(c.upcase).include? letter}.first 
    puts "'#{letter}': #{ letter_class || "something else"}" 
end 

輸出:

'a': vowel 
'b': consonant 
'c': consonant 
'd': consonant 
'e': vowel 
'f': consonant 
'1': something else 
'2': something else 
'3': something else 
'4': something else 
'5': something else 

多圖示和字符文字只能在1.9中使用。

+0

您對splat運算符的使用比我的更加密集和更好。 – sawa 2011-05-24 00:24:55

2

你讓我困惑的代碼,因爲SimpleLetter應該是單個字母,而不是整個字母表。

我會都特別想做到以下幾點,儘管是的monkeypatching一個有點冒險:

module Voweliness 
    def vowel? 
    self =~ /[aeiou]/i 
    end 

    def consonant? 
    (self =~ /[a-z]/i and not vowel?) 
    end 
end 

class String 
    include Voweliness 
end 


objects.each do |letter| 
    case 
    when letter.vowel? 
     puts "#{letter} is a vowel" 
    when letter.consonant? 
     puts "#{letter} is a consonant" 
    else 
     puts "#{letter} is something else" 
    end 
end 
相關問題