我正在开始ruby书,这是我的代码,它给出了以下错误:
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
Run Code Online (Sandbox Code Playgroud)
您发布的错误意味着此行......
@rm.full_description
Run Code Online (Sandbox Code Playgroud)
...正试图调用full_description没有这种方法的@rm对象,因为对象是nil.从那以后我们可以推断出前一行......
@rm=find_room_in_dungeon(@player.location)
Run Code Online (Sandbox Code Playgroud)
...设置@rm到nil作为结果find_room_in_dungeon的方法.如果我们看看那种方法......
@rooms.detect{|room| room.reference == reference; puts room.full_description}
Run Code Online (Sandbox Code Playgroud)
......我们看到一个问题.该detect方法使用块的返回值来确定是否应该使用房间.但是,该puts方法(它是块中的最后一个,因此块的返回值)总是返回nil.因此,@rooms.detect永远不会找到任何东西.所以让我们通过puts完全删除来解决这个问题:
@rooms.detect{|room| room.reference == reference }
Run Code Online (Sandbox Code Playgroud)
这应该有所帮助,但它没有解决问题.我们仍然nil从这种方法中获益.让我们看一下.
首先,让我们验证我们关于这种方法的前提条件的假设.在更改行之前,我们添加p @rooms, reference到find_room_in_dungeon方法中.现在运行代码,我们看到这个输出:
[]
:small_cave
Run Code Online (Sandbox Code Playgroud)
啊,哈!这就是问题所在.我们正在寻找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>'
Run Code Online (Sandbox Code Playgroud)
啊,哈!问题是,在我们有机会为地牢添加房间之前,我们称之为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
Run Code Online (Sandbox Code Playgroud)不要将当前描述显示为初始化程序的一部分.只需删除该行,并在运行时显示构造完成时的描述:
d = Dungeon.new(...)
d.add_room(...)
d.add_room(...)
d.show_current_description
Run Code Online (Sandbox Code Playgroud)使您的show_current_description方法更健壮,以便它可以处理nil案例:
def show_current_description
@rm = find_room_in_dungeon(@player.location)
puts @rm.full_description if @rm
end
Run Code Online (Sandbox Code Playgroud)你可以选择做1或2,但我建议做3.
| 归档时间: |
|
| 查看次数: |
4093 次 |
| 最近记录: |