我有这个简单的测试:
def swap(a, b)
c = a
a = b
b = c
end
a = 3
b = 4
swap(a, b)
print a # 3. not change value
我知道这个例子不适用于某些语言,例如Java或C#,因为这些变量是基元。但是在Ruby中,如果一切都是对象,我认为上面的例子应该可行。请向我解释一下。
我认为问题是因为FixNum是不可变的。我有一个概念验证代码使用Java来创建一个不可变的整数类:
static class CustomInteger {
Integer value;
public CustomInteger(int i) {
this.value = i;
}
public void changeValue(int i) {
this.value = i;
}
public int getValue() {
return value;
}
public CustomInteger setValueImmutable(int i) {
return new CustomInteger(i);
}
}
public static void swap(CustomInteger a, CustomInteger b) {
int c = a.getValue();
a.changeValue(b.getValue());
b.changeValue(c);
}
public static void main(String[] args) {
CustomInteger i1 = new CustomInteger(3);
CustomInteger i2 = new CustomInteger(4);
swap(i1, i2);
System.out.println(i1.getValue());
}
public static void notWorkSwap(Integer a, Integer b) {
int temp_a = a;
int temp_b = b;
a = temp_b;
b = temp_a;
}
答案 0 :(得分:3)
您的swap
方法仅交换方法本地的变量。
在方法内部,a
和b
被交换。但是,这不会影响方法之外的任何内容。 c
未在swap
之外定义。
请注意,要交换a
和b
,您不需要任何其他变量:a, b = b, a
是一种有效的Ruby语法。
最后,变量aren't objects。他们只是引用对象。
这是实现您想要做的事情的一种方式。 更新:它基本上相当于您的Java代码:
class MyObject
attr_accessor :x
def initialize(x)
@x = x
end
end
def swap(f,g)
f.x, g.x = g.x, f.x
end
a = MyObject.new(1)
b = MyObject.new(2)
swap(a, b)
puts a.x
#=> 2
puts b.x
#=> 1
请注意,对象a
和b
尚未交换。但是,他们的x
值已被交换。
另一种可能性是使用实例变量:
def swap
@a, @b = @b, @a
end
@a = 1
@b = 2
swap
p @a
#=> 2
p @b
#=> 1
答案 1 :(得分:2)
这不起作用的原因是方法参数是按值传递的,而不是通过引用传递的。默认情况下,只有少数语言使用pass-by-reference语义。 Java和Ruby中的行为是相同的。
然而,这很麻烦,很多人滥用这个术语。例如,请参阅此问题。 Is Java "pass-by-reference" or "pass-by-value"?
在许多语言中,例如C#,可以使用特殊关键字进行传递引用(在C#的情况下为ref,或者在C ++中的类型之后为& marker)。您可以通过传递间接指针来模拟C语言中的行为(尽管这样可以提供更多功能,这要归功于不太严格的类型检查)。
我在几年内没有编写C#代码,但你想要达到的目标是:
static void SwapStrings(ref string s1, ref string s2)
{
string temp = s1;
s1 = s2;
s2 = temp;
}
将调用SwapStrings(ref str1, ref str2);
此代码是此处的缩写版本:https://msdn.microsoft.com/en-us/library/s6938f28.aspx