我正在做一本红宝石书,这就是我的代码,它给出了以下错误:
in 'show_current_description': undefined method 'full_description' for nil:NilClass (NoMethodError)
代码如下。任何帮助表示赞赏。谢谢!
class Dungeon
attr_accessor :player
def initialize(player_name,start_location)
@player=Player.new(player_name,start_location)
puts @player.location
@rooms=[]
show_current_description
end
def show_current_description
@rm=find_room_in_dungeon(@player.location)
@rm.full_description
end
def find_room_in_dungeon(reference)
@rooms.detect{|room| room.reference == reference; puts room.full_description}
end
def add_room(reference,name,description,connections)
@rooms << Room.new(reference,name,description,connections)
end
Player=Struct.new(:name,:location)
class Room
attr_accessor :reference, :name, :description, :connections
def initialize(reference,name,description,connections)
@reference=reference
@name=name
@description=description
@connections=connections
end
def full_description
"You are in " + @description
end
end
end
d=Dungeon.new("Good Man",:small_cave)
d.add_room(:small_cave,"Small Cave","This is a small claustrophobic cave", {:east => :largecave})
d.add_room(:large_cave,"Large Cave","This is a large cavernous cave", {:west => :smallcave})
puts d.player.name
d.show_current_description
答案 0 :(得分:6)
您发布的错误表示此行...
@rm.full_description
...正在尝试在没有此类方法的对象上调用full_description
,因为@rm
对象是nil
。由此我们可以推断出前一行......
@rm=find_room_in_dungeon(@player.location)
...将@rm
设置为nil
作为find_room_in_dungeon
方法的结果。如果我们看一下这种方法......
@rooms.detect{|room| room.reference == reference; puts room.full_description}
......我们看到一个问题。 detect
方法使用块的返回值来确定是否应该使用房间。但是,puts
方法(块中的最后一个方法,因此块的返回值)始终返回nil
。因此,@rooms.detect
永远不会找到任何东西。因此,让我们通过完全删除puts
来解决这个问题:
@rooms.detect{|room| room.reference == reference }
这应该有所帮助,但它没有解决问题。我们仍然从此方法获得nil
。让我们看一下。
首先,让我们验证我们对这种方法的前提条件的假设。在更改行之前,我们会向p @rooms, reference
方法添加find_room_in_dungeon
。现在运行代码,我们看到了这个输出:
[]
:small_cave
阿公顷!这就是问题所在。我们正在寻找small_cave
房间,但我们的房间清单是空的!我们知道我们在脚本的底部调用d.add_room
...为什么它不起作用?
让我们看看这段代码破坏时的位置。以下是错误消息的完整回溯:
C:/tmp.rb:13:in `show_current_description': undefined method `full_description' for nil:NilClass (NoMethodError)
from C:/Users/gkistner.NVIDIA.COM/Desktop/tmp.rb:8:in `initialize'
from C:/Users/gkistner.NVIDIA.COM/Desktop/tmp.rb:43:in `new'
from C:/Users/gkistner.NVIDIA.COM/Desktop/tmp.rb:43:in `<main>'
阿-HA!问题是,在我们有机会为地牢添加房间之前,我们会将show_current_description
作为initialize
方法的一部分。
以下是我们解决此问题的一些方法:
更改Dungeon构造函数以接受房间列表作为初始化的一部分,因此我们可以一次完成所有操作。以下是三种不同的方式:
# Method number one, accept an array of rooms
class Dungeon
def initialize(name,start,rooms=[])
@player = ...
@rooms = rooms
yield(self) if block_given?
show_current_description
end
end
d = Dungeon.new( "Bob", :small_cave, [
Dungeon::Room.new(...),
Dungeon::Room.new(...)
] )
# Method 2: Allow an initializer block
class Dungeon
def initialize(name,start)
@player = ...
@rooms = []
yield(self) if block_given?
show_current_description
end
end
d = Dungeon.new( "Bob", :small_cave ) do |dungeon|
dungeon.add_room(...)
dungeon.add_room(...)
end
# Method 3 (experts only!): Initialize block runs in scope
class Dungeon
def initialize(name,start,&initializer)
@player = ...
@rooms = []
instance_eval(&initializer) if initializer
show_current_description
end
end
d = Dungeon.new( "Bob", :small_cave ) do
add_room(...)
add_room(...)
end
不要将当前描述显示为初始化程序的一部分。只需删除该行,并在运行时在构造完成时显示描述:
d = Dungeon.new(...)
d.add_room(...)
d.add_room(...)
d.show_current_description
让您的show_current_description
方法更加健壮,以便它可以处理nil
案例:
def show_current_description
@rm = find_room_in_dungeon(@player.location)
puts @rm.full_description if @rm
end
你可以选择做1或2,但我建议也做3。
答案 1 :(得分:1)
底部的第4行@rooms :largecave})
是语法错误。真正的代码肯定看起来不同。
无论如何,“nil:NilClass的未定义方法full_description”表示由find_room_in_dungeon
返回的@rm为零。
答案 2 :(得分:0)
您是否删除了@ rooms.detect {...}中的看跌期权?
删除它,它应该可以工作。