Ruby 和指针与其他语言相比?

dar*_*der 4 c++ ruby arrays

我对 ruby​​ 相当陌生,但有 C/C++ 背景,我相信我对计算机和编程的工作原理有基本了解。

在 C++ 中,如果您想创建一个指向某个值的指针,您可以将其指定为指针:http://www.cplusplus.com/doc/tutorial/pointers/

例子:

int x = 3;
int *p = &x;
*p = 4;
std::cout << x;
Run Code Online (Sandbox Code Playgroud)

这对我来说很有意义,因为现在p指向 的地址x,因此当我们更改 的值时px也会发生变化。x在这种情况下将输出 4。

但是当我跑步时:

a = []
b = a
a[0] = 3
p b
# => [3]

c = "this is a string"
d = c
c.upcase!
c = "the string has been edited"
p d
# => THIS IS A STRING
Run Code Online (Sandbox Code Playgroud)

在红宝石中,b输出[3]对我来说不应该输出任何内容。并且d输出"THIS IS A STRING"而不是"the string has been edited"Ruby 和指针是另一个问题,其中介绍了如何在 Ruby 中使用指针。

我的问题是:为什么数组在 ruby​​ 中被视为指针以及它是如何工作的?是像C++中那样b指向 的a地址吗?是什么让变量改变它所指向的内容?例如:如果a = b什么时候a != b?为什么整数不指向另一个变量的地址?

Jör*_*tag 5

为什么数组在 ruby​​ 中被视为指针以及它是如何工作的?

他们不是。Ruby 中没有“指针”这样的东西。

是像C++中那样b指向 的a地址吗?

Ruby 中没有“地址”这样的东西。语言规范规定,当您取消引用变量时,它将计算分配给该变量的最后一个对象。语言实现如何做到这一点是完全无关的,你不应该,事实上也不可能知道它。它可以使用指向内存位置的指针。它可以使用字典。它可以将价值打印在纸上,然后传真到东亚的一家血汗工厂,由童奴对其进行解读。(这将是非常不道德、不道德和非法的,但它是一个完全有效的实施。)

是什么让变量改变它所指向的内容?

赋值,并且只有赋值才能改变变量的绑定。

例如:如果a = b什么时候a != b

!=方法被重写时这样说。这将是一个糟糕的主意,但尽管如此:

class Foo
  def !=(*)
    false
  end
end

a = Foo.new
b = a

a != b #=> false
Run Code Online (Sandbox Code Playgroud)

为什么整数不指向另一个变量的地址?

同样,Ruby 中不存在“指针”或“地址”这样的东西,因此,整数永远不能“指向”“地址”,仅仅是因为“指向”和“地址”不是存在于 Ruby 中的概念。红宝石。

让我们逐行查看您的代码:

a = []
Run Code Online (Sandbox Code Playgroud)

您创建一个新Array对象并将局部变量绑定a到该新数组对象。

b = a
Run Code Online (Sandbox Code Playgroud)

现在,您将局部变量绑定b到表达式 的求值结果a。计算仅包含变量名称的表达式的结果是什么?该变量被取消引用,即它计算为先前绑定到该变量的对象。

在本例中,该对象是Array您在第 1 行创建的对象。

a[0] = 3
Run Code Online (Sandbox Code Playgroud)

该行只是以下行的语法糖:

a.[]=(0, 3)
Run Code Online (Sandbox Code Playgroud)

[]=在这里,您将发送传递两个参数的消息0以及3取消引用局部变量的结果a。同样,取消引用局部变量的a结果是该变量绑定到最后一个变量,即第Array1 行。该方法Array#[]=被定义为改变其接收者,以便将其第二个参数放置在第一个参数指定的索引处。

该方法不必改变其接收者。它还可以返回Array. (尽管在这种特殊情况下,这将是无用的,因为a[0] = 3语法糖的行为类似于赋值,因此将始终评估右侧。换句话说,Array#[]=除非您使用显式方法调用语法,否则将忽略 的返回值a.[]=(0, 3)。)

p b
Run Code Online (Sandbox Code Playgroud)

在这里,我们再次取消引用局部变量b,它仍然指向完全相同的对象(从来没有任何重新分配),它仍然是来自Array第 1 行的对象。

Array整个代码中只有一首单曲。您从未创建过第二个,也从未调用过会返回新的方法Array

一种确实返回新值Array而不是改变接收器的方法是 method Array#+。这是一个使用的替代示例Array#+

a = []
b = a
a += [3]
Run Code Online (Sandbox Code Playgroud)

a += [3]相当于a = a + [3]相当于a = a.+([3])。因此,我们取消引用a,它给出了第 1 行的 ,然后我们向它发送带有单个参数 的Array消息。定义为返回一个新的,它是接收者和参数的串联。最后,我们将这个 new 赋给局部变量。+[3]Array#+ArrayArraya

p b
Run Code Online (Sandbox Code Playgroud)

局部变量b仍然绑定到同一个对象,因为我们从未重新分配它。因此,它仍然绑定到Array第 1 行。我们从未更改过此内容Array,因此,此打印[]

关于你的第二个例子(这次我会更快一点):

c = "this is a string"
Run Code Online (Sandbox Code Playgroud)

创建一个新的String,分配给c.

d = c
Run Code Online (Sandbox Code Playgroud)

绑定d到任何c绑定的内容,即String来自第 1 行的内容。

c.upcase!
Run Code Online (Sandbox Code Playgroud)

将消息发送upcast!String通过取消引用获得的cString#upcase!被定义为改变接收者。因此,String两者都引用了 that cd现在已经改变了本身。

c = "the string has been edited"
Run Code Online (Sandbox Code Playgroud)

String创建一个与另一个无关的全新并将其分配给c.

p d
Run Code Online (Sandbox Code Playgroud)

d从未被重新分配过,因此,它仍然绑定到String第 1 行。