简体   繁体   中英

Why is this case when not working properly?

  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?

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 (ie 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM