【问题标题】:Why Dart is acting as pass by reference?为什么 Dart 充当引用传递?
【发布时间】:2020-09-26 17:02:20
【问题描述】:

我知道 dart 就像 Java 一样按值传递,但我不明白为什么在下面的示例中它的行为类似于按引用传递?

class A {
  int y = 10;
}

class B {
  List<A> list = [];
  void add(A a) {
    a.y = 20;
    list.add(a);
  }

  void runtest() {
    print(list[0].y);
  }
}

void main() {
  A a = A();
  B b = B();
  b.add(a);
  print(a.y);
  b.runtest();
}

结果是

20
20

为什么当对象 (a) 的变量 (y) 在 (b) 内部的方法 (add) 内部发生变化时,它也改变了对象 (a) 在 main() 内部的变量 (y)?

【问题讨论】:

标签: dart pass-by-reference pass-by-value


【解决方案1】:

Dart 是按值调用的。 是对象引用。这有时也称为"call by sharing" 或“按对象引用调用”。它是按值调用...用于特定的值选择。

对象具有身份,这是面向对象编程的基本基石之一。正因为如此,你不能复制它们而不把它变成一个新的对象。这就是为什么面向对象的语言通常不将对象存储在变量中,它们存储对对象的引用。然后这些引用按值传递。

按值调用与按引用调用的不同之处在于后者传递变量(也称为左值,赋值左侧的东西),而不是它们的值( R 值)。 Call-by-reference 允许您创建一个局部变量,通过引用将其传递给另一个函数,并让该函数更改绑定到该变量的值。 Dart 做不到,它只能传递变量的值。

对象可以包含变量(实例变量,又名字段),因此您可以将引用传递给包含变量的对象(按值),这允许函数通过参数改变 something ,但不能是局部变量。

【讨论】:

    【解决方案2】:

    我认为您的困惑来自对什么是变量和参数以及按引用传递和按值传递的概念的误解。

    Dart 中的变量可以看作是对对象的引用。当您将此变量作为参数提供给方法时,您必须提供此引用的副本。因此,该方法不能更改此引用指向的对象。但是该方法确实可以访问对象本身,因为它获得了引用的副本。因此,当我们为方法提供变量时,我们不会创建对象的副本。

    Dart 中的某些对象是不可变的(如 String、int、double 等),因此方法将无法更改这些类型对象的内部状态。因此,即使我们获得了对其中一些对象的引用副本,我们也无法更改状态,因此我们看到这类似于“按值传递”行为。

    但是如果一个对象(例如List)能够改变它的内部状态,我们可以进行修改,比如向List对象添加项目。由于我们从不创建新对象,我们将在我们的方法之外看到这种变化,因为我们已经对对象本身进行了更改,而没有对引用进行任何更改。这给出了您在示例中看到的这种“通过引用”行为。

    但这并没有改变变量本身是一个引用的事实,当将其作为参数提供给方法时,它总是“按值传递”。

    当我们谈论方法的参数时,一个小例子展示了我所说的“按值传递”的含义,可以在这里看到:

    class A {
      int value;
    
      A(this.value);
    }
    
    void main() {
      final a = A(1);
      print(a.value); // 1
      myMethod(a);
      print(a.value); // 1
    }
    
    void myMethod(A a) {
      a = A(2);
    }
    

    如示例所示,myMethod 中的 a 变量可以更改为指向另一个对象,但由于该变量是按值传递的,因此 main 中不会发生更改。

    【讨论】:

      猜你喜欢
      • 2011-09-30
      • 2021-11-21
      • 1970-01-01
      • 2015-12-29
      • 2012-05-05
      • 2017-05-15
      • 1970-01-01
      • 2020-09-26
      • 2016-03-31
      相关资源
      最近更新 更多