开发者

Delete Instance Variables from Objects in an Array

开发者 https://www.devze.com 2023-03-30 23:41 出处:网络
I\'m new to Ruby and I\'m just having a play around with ideas and what I would like to do is remove the @continent data from the country_array I have created.Done a good number of searches and can fi

I'm new to Ruby and I'm just having a play around with ideas and what I would like to do is remove the @continent data from the country_array I have created. Done a good number of searches and can find quite a bit of info on removing elements in their entirety but can't find how to specifically remove @continent data. Please keep any answers fairly simple as I'm new, however any help much appreciated.

class World
  include Enumerable
  include Comparable

  attr_accessor :continent
  def <=> (sorted)
    @length = other.continent
  end

  def initialize(country, continent)
    @country = country
    @continent = continent
  end 
end开发者_StackOverflow

a = World.new("Spain", "Europe")
b = World.new("India", "Asia")
c = World.new("Argentina", "South America")
d = World.new("Japan", "Asia")

country_array = [a, b, c, d]

puts country_array.inspect

[#<World:0x100169148 @continent="Europe", @country="Spain">, 
#<World:0x1001690d0 @continent="Asia", @country="India">, 
#<World:0x100169058 @continent="South America", @country="Argentina">, 
#<World:0x100168fe0 @continent="Asia", @country="Japan">]


You can use remove_instance_variable. However, since it's a private method, you'll need to reopen your class and add a new method to do this:

class World
  def remove_country
    remove_instance_variable(:@country)
  end
end

Then you can do this:

country_array.each { |item| item.remove_country }
# => [#<World:0x7f5e41e07d00 @country="Spain">, 
      #<World:0x7f5e41e01450 @country="India">, 
      #<World:0x7f5e41df5100 @country="Argentina">, 
      #<World:0x7f5e41dedd10 @country="Japan">] 


The following example will set the @continent to nil for the first World object in your array:

country_array[0].continent = nil

irb(main):035:0> country_array[0]
=> #<World:0xb7dd5e84 @continent=nil, @country="Spain">

But it doesn't really remove the continent variable since it's part of your World object.

Have you worked much with object-oriented programming? Is your World example from a book or tutorial somewhere? I would suggest some changes to how your World is structured. A World could have an array of Continent's, and each Continent could have an array of Country's.

Names have meaning and variable names should reflect what they truly are. The country_array variable could be renamed to world_array since it is an array of World objects.


99% of the time I would recommend against removing an instance variable, because it's extra code for no extra benefit.

When you're writing code, generally you're trying to solve a real-world problem. With the instance variable, some questions to ask are:

  • What real world concept am I trying to model with the various states the variable can be in?
  • What am I going to do with the values stored in the variable?

If you're just trying to blank out the continent value stored in a World object, you can set @continent to nil as dustmachine says. This will work fine for the 99% of the cases. (Accessing a removed instance variable will just return nil anyway.)

The only possible case (I can think of) when removing the instance variable could be useful is when you're caching a value that may be nil. For example:

class Player
  def score(force_reload = false)
    if force_reload
      # purge cached value
      remove_instance_variable(:@score)
    end

    # Calling 'defined?' on an instance variable will return false if the variable
    # has never been set, or has been removed via force_reload.
    if not defined? @score
      # Set cached value.
      # Next time around, we'll just return the @score without recalculating.
      @score = get_score_via_expensive_calculation()
    end

    return @score
  end

  private
  def get_score_via_expensive_calculation
    if play_count.zero?
      return nil
    else
      # expensive calculation here
      return result
    end
  end
end

Since nil is a meaningful value for @score, we can't use nil to indicate that the value hasn't been cached yet. So we use the undefined state to tell us whether we need to recalculate the cached value. So there are 3 states for @score:

  1. nil (means user has not played any games)
  2. number (means user played at least once but did not accrue any points)
  3. undefined (means we haven't fetched the calculated score for the Player object yet).

Now it's true that you could use another value that's not a number instead of the undefined state (a symbol like :unset for example), but this is just a contrived example to demonstrate the idea. There are cases when your variable may hold an object of unknown type.

0

精彩评论

暂无评论...
验证码 换一张
取 消