如果一切都是对象,为什么我不能交换两个变量?

时间:2017-02-01 17:16:24

标签: java ruby object

我有这个简单的测试:

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;
    }

2 个答案:

答案 0 :(得分:3)

您的swap方法仅交换方法本地的变量。

在方法内部,ab被交换。但是,这不会影响方法之外的任何内容。 c未在swap之外定义。

请注意,要交换ab,您不需要任何其他变量: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

请注意,对象ab尚未交换。但是,他们的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