1

在 PHP 中,我可以使用&reference一个变量的 分配给另一个变量,如下面的第一个代码片段所示。

有关更多上下文,请参阅 PHP“返回参考”文档... http://www.php.net/manual/en/language.references.return.php

PHP代码:

<?php
  $tree = array();
  $tree["branch"] = array();
  $tree["branch"]["leaf"] = "green";

  echo '$tree: ';
  var_dump($tree);

  $branch = &$tree["branch"];

  $branch = "total replacement!";

  echo '$tree: ';
  var_dump($tree);
?>

PHP的输出:

$tree: array(1) {
  ["branch"]=>
  array(1) {
    ["leaf"]=>
    string(5) "green"
  }
}
$tree: array(1) {
  ["branch"]=>
  &string(18) "total replacement!"
}

尝试在 Ruby 中执行此操作,我做到了:

tree = {}
tree["branch"] = {}
tree["branch"]["leaf"] = "green"

puts "tree: #{tree.inspect}"

branch = tree["branch"]

branch = "total replacement!"

puts "tree: #{tree.inspect}"

哪个输出:

tree: {"branch"=>{"leaf"=>"green"}}
tree: {"branch"=>{"leaf"=>"green"}}

现在,虽然这种直接赋值在 Ruby 中不起作用,但修改对象可以:

Ruby 代码(续):

branch["lead"] = "red"
puts "tree: #{tree.inspect}"

红宝石的输出:

tree: {"branch"=>{"leaf"=>"red"}}

所以,我想知道是否有办法找到一个对象的“父”,这样我就可以像修改它一样修改它branch["leaf"]

作者编辑:

虽然不能通过x = y赋值(例如)更改对任何其他变量的散列引用,但可以通过其方法修改现有对象。使用这种方法,可以使用如下所示将新变量伪分配给hash变量...branch.replace()

替换而不是分配:

tree = {}
tree["branch"] = {}
tree["branch"]["leaf"] = "green"

puts "tree: #{tree.inspect}"

branch = tree["branch"]

branch.replace({"leaf" => "red", "twig" => "brown"})

puts "tree: #{tree.inspect}"

输出:

tree: {"branch"=>{"leaf"=>"green"}}
tree: {"branch"=>{"leaf"=>"red", "twig"=>"brown"}}
4

2 回答 2

1

一个变量可以存储一个键

Ruby 方法不是尝试使用间接引用或Kernel#eval,而是使用变量或表达式来存储或定义您需要的键。这与您的 PHP 代码不太一样,但您当然可以使用 Ruby 的本机 Hash 方法来查找给定值的键。

找到你想要的钥匙

我想知道是否有一种方法可以找到对象的“父级”,以便我可以像使用分支 [“叶”] 一样修改它。

考虑散列的性质:散列中的每个键都必须是唯一的,尽管嵌套散列的键可以与父散列或兄弟散列中的键相同。例如:

# Keys for nested hashes can be the same.
tree = {
  branch1: { leaf: 'green' },
  branch2: { leaf: 'red'   },
}
#=> {:branch1=>{:leaf=>"green"}, :branch2=>{:leaf=>"red"}}

# Duplicate keys; last one "wins."
tree = {
  branch: { leaf: 'green' },
  branch: { leaf: 'red'   },
}
#=> {:branch=>{:leaf=>"red"}

从好的方面来说,这意味着任何给定的散列级别都将有一个与您想要的匹配的键。有很多方法可以找到它。一个示例是使用Hash#rassoc返回您想要的密钥:

tree.rassoc( {leaf: 'red'} ).first
#=> :branch2

#select#each_pair等其他方法也可能有用,具体取决于您的需求和您要表达的语义。

使用键名

获得密钥后,您可以使用该密钥修改该密钥的关联值。例如:

tree = {
  branch1: { leaf: 'green' },
  branch2: { leaf: 'red'   },
}
key = tree.rassoc( {leaf: 'red'} ).first
tree[key] = { leaf: 'blue' }
tree
#=> {:branch1=>{:leaf=>"green"}, :branch2=>{:leaf=>"blue"}}
于 2013-05-23T04:19:51.063 回答
0

For starters, Ruby is pass by reference. Think of it this way - this line:

branch = tree["branch"]

is creating a second reference to the underlying hash you created here:

tree["branch"] = {}

Those references are the:

  1. local branch variable.
  2. hash value in the tree hash for key branch.

By assigning a different value to the local variable branch, you're removing one reference, e.g. you're changing the reference holder not the reference itself. In Ruby you wouldn't expect the reference in the hash to change when a totally separate reference changed.

Some objects support operations that allow you to update them in-place, hashes for instance, but there is no facility I'm aware of to perform cascading reference changes like you're describing (e.g. change all references to an object to some other object).

于 2013-05-23T02:36:44.390 回答