提问人:MR-RenatoBlue 提问时间:5/17/2023 更新时间:5/18/2023 访问量:64
为什么当我调用一个函数时,一个传递对数组的引用,数组在 Ruby 中发生了变化?[关闭]
why when I call a function passing a reference to an array, the array is changing in ruby? [closed]
问:
我正在学习一个关于在 Ruby 中创建一个小游戏的教程,当时我遇到了一个我无法理解的错误。当我仔细观察时,我意识到错误发生在 on 的 51 行。
在本教程的这一点上,英雄“H”应该能够使用键“ASDW”四处走动。我注意到第 49 行的数组已更改,这在应用程序中引入了错误。之后,我创建了另一个变量,该变量调用了代码。
为什么当我调用 的第 51 行时,数组正在更改?
从我在 Rubydocs 中读到的内容来看,我只是不明白为什么会发生这种情况。fogefoge.rb
nova_posicao = calcula_nova_posicao heroi, direcao
heroi
heroi = encontra_jogador mapa
heroi2
fogefoge.rb
File "main.rb"
require_relative "fogefoge"
inicia_fogefoge
File "mapa1.txt"
XXXXX
X H X
X X X
X X X
X X
X
XXX
X
X F X
XXXXX
File "ui.rb"
def da_boas_vindas
puts "bem vindo ao Foge-foge"
puts "Qual é o seu nome?"
nome = gets.strip
puts "\n\n\n\n\n"
puts "Começaremos o jogo para você, #{nome}"
nome
end
def desenha(mapa)
puts mapa
end
def pede_movimento
puts "Para onde deseja ir?"
movimento = gets.strip
end
#File "fogefoge.rb"
require_relative "ui"
def le_mapa(numero)
arquivo = "mapa#{numero}.txt"
texto = File.read(arquivo)
mapa = texto.split "\n"
# p mapa
end
def encontra_jogador(mapa)
caractere_do_heroi = "H"
mapa.each_with_index do |linha_atual, linha|
coluna_do_heroi = linha_atual.index caractere_do_heroi
if coluna_do_heroi
return [linha, coluna_do_heroi]
end
end
end
def calcula_nova_posicao(heroi, direcao)
case direcao
when "W"
heroi[0] -= 1
when "S"
heroi[0] += 1
when "A"
heroi[1] -= 1
when "D"
heroi[1] += 1
end
heroi
end
def posicao_valida?(mapa, posicao)
linhas = mapa.size
colunas = mapa[0].size
estourou_linhas = posicao[0] < 0 || posicao[0] >= linhas
estourou_colunas = posicao[1] < 0 || posicao[1] >= colunas
if estourou_linhas || estourou_colunas
return false
end
if mapa[posicao[0]][posicao[1]] == "X"
return false
end
true
end
def joga(nome)
mapa = le_mapa 1
while true
desenha mapa
direcao = pede_movimento
heroi = encontra_jogador mapa
#heroi2 = encontra_jogador mapa
nova_posicao = calcula_nova_posicao heroi, direcao #At this call
if !posicao_valida? mapa, nova_posicao
next
end
mapa[heroi[0]][heroi[1]] = " "
mapa[nova_posicao[0]][nova_posicao[1]] = "H"
end
end
def inicia_fogefoge
nome = da_boas_vindas
joga nome
end
我本以为“H”会在空白处四处移动,但“H”被重复到几个方向
输出:
bem vindo ao Foge-foge
Qual é o seu nome?
marcos
Começaremos o jogo para você, marcos
XXXXX
X H X
X X X
X X X
X X
X
XXX
X
X F X
XXXXX
Para onde deseja ir?
d
XXXXX
X H X
X X X
X X X
X X
X
XXX
X
X F X
XXXXX
Para onde deseja ir?
D
XXXXX
X HHX
X X X
X X X
X X
X
XXX
X
X F X
XXXXX
Para onde deseja ir?
S
XXXXX
X HHX
X X X
X X X
X X
X
XXX
X
X F X
如果取消注释第 50 行的第二个引用,然后将第 51 行更改为,则代码将起作用。nova_posicao = calcula_nova_posicao heroi2, direcao
答:
您的实现会更改传递的数组,然后返回它。因此,调用后 your 和 将是相同的(不仅包含相同的值,而且都引用相同的对象)。calcula_nova_posicao
heroi
nova_posicao
heroi
下面是一个关于如何验证这一点的简单示例:(equal?
检查两个对象是否实际上是同一个对象)
a = [0, 0]
b = calcula_nova_posicao(a, "S")
a #=> [1, 0] <- note that "a" has changed!
b #=> [1, 0]
a.equal?(b) #=> true
为什么当我调用一个函数时,一个传递对数组的引用,数组在 Ruby 中发生了变化?
这是 Ruby 中一个非常基本的行为。有些对象是可变的,即您可以通过向它们发送某些消息来更改这些对象(所谓的破坏性方法)。可变对象的示例包括字符串、哈希和数组。(破坏性)消息的发送方式或位置或谁发送都无关紧要。一旦接收到,该物体就会自行改变。
下面是两个变量的示例,它们引用了同一个对象,即一个字符串。如果将 upcase!
消息发送到字符串,它将将其字符大写,并且两个变量都将反映该更改:(因为它们仍然引用现在已更改的同一对象)a
b
a = "foo"
b = a
a.upcase! # or b.upcase!
a #=> "FOO"
b #=> "FOO"
这同样适用于方法参数。如果将可变对象传递到方法中,则该方法可以更改它,就像在方法外部一样:
def my_method(s)
s.upcase!
end
a = "foo"
my_method(a)
a #=> "FOO"
回到你的问题。您可能希望 1) 返回一个新数组,2) 保持传入的数组不变。后者对于清除地图中的电流很重要。但一般来说,不要在方法中更改参数也是一个好主意,因为它可能会导致意外的结果并且很难找到错误。calcula_nova_posicao
H
下面是一个实现:
def calcula_nova_posicao(heroi, direcao)
case direcao
when "W"
[heroi[0] - 1, heroi[1]]
when "S"
[heroi[0] + 1, heroi[1]]
when "A"
[heroi[0], heroi[1] - 1]
when "D"
[heroi[0], heroi[1] + 1]
end
end
这是另一个使用数组分解的方法:
def calcula_nova_posicao(heroi, direcao)
y, x = heroi
case direcao
when "W" then y -= 1
when "S" then y += 1
when "A" then x -= 1
when "D" then x += 1
end
[y, x]
end
您可以考虑为您的方法编写测试。
评论