Why is this case when not working properly?

别等时光非礼了梦想. 提交于 2020-06-09 04:15:29

问题


  if ( item::class == RPG::Weapon )
    print "yup"
  end
  case item::class
  when RPG::Item
    type = 0
  when RPG::Weapon
    type = 1
  when RPG::Armor
    type = 2
  else
    type = 10
  end

I'm new to Ruby. The if statement runs fine and prints "yup", but the case statement isn't working properly and sets type to 10. Am I blind to something or what?


回答1:


Module#=== tests if the argument is an instance of self. item.class can never be an instance of anything but Class, in particular, it will never be an instance of either RPG::Weapon or RPG::Armor, therefore none of the when branches will ever match and you will always get the else branch.

By the way: using the namespace resolution operator :: for message sends instead of the message sending operator . is extremely un-idiomatic and confusing (and won't work for methods whose name starts with an uppercase character). In fact, I believe matz considers adding this feature to Ruby a mistake.

Note also that case is an expression, in fact, everything in Ruby is an expression.

I would write the code as follows:

type = case item
  when RPG::Item
    0
  when RPG::Weapon
    1
  when RPG::Armor
    2
  else
    10
end

However, in general, conditionals are a code smell. Ruby is an object-oriented language, polymorphism (i.e. method dispatching based on the type of self) is all the conditional you need! In fact, in this very example, you are manually examining the class of item in order to determine its type, but that is exactly what method dispatch does anyway! Personally, I would refactor this code like this:

class RPG::Item
  def type
    0
  end
end

class RPG::Weapon
  def type
    1
  end
end

class RPG::Armor
  def type
    2
  end
end

class RPG::Object # or whatever your baseclass is
  def type
    10
  end
end

Now when you add a new kind of game object, you don't have to modify your existing code by adding a new branch to your case expression. You just add the new class, without needing to modify any existing code.




回答2:


Just case item will be sufficient - no need for case item::class.

Case matching in Ruby is done with a fuzzy matching (===) algorithm that doesn't need such specific clauses.



来源:https://stackoverflow.com/questions/30554856/why-is-this-case-when-not-working-properly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!