Dart 中,参数传递的方式是值传递还是引用传递?

567 阅读2分钟

基本数据类型的传递(按值传递)

 void main() {
  int num = 5;
  modifyValue(num);
  debugPrint('---😆😆num1:$num😆😆---'); // 输出:5   
 }
  
  
 void modifyValue(int value) {
  value = 10;
  debugPrint('---😆😆num2:$value 😆😆---'); // 输出:10
 }

打印日志, 可以看出, 基本数据类型变量传递给函数, 相当于将这个变量复制一份, 然后将副本传递给函数, 在函数内部修改这个变量, 并不会影响原始变量

引用类型的传递(List、Map、Object按引用传递)

class A {
  int y = 10;
}

class B {
  List<A> list = [];
  
  void add(A a) {
    // 更改对象a内部的y属性
    a.y = 20;
    list.add(a);
  }

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

会影响原始对象
void main() {
  final A a = A();
  final B b = B();
  b.add(a);
  print(a.y); /// 输出:20
  b.runtest(); /// 输出:20
}

打印日志, 可以看出, 传递了一个Object类型对象给函数, 相当于将这个对象的地址传递给了函数, 函数修改了这个地址指向的对象里的一个变量值后, 影响到原始对象了。这个地址相当于一个点, main函数引了一条线, 给外部函数的是另外一条线, 另外一条线修改了地址指向的对象里的值, 那么, main函数引用的这条线的值也会跟着变化。

Object按值传递

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
 final a = A(2);
 print(a.value); // 2
}

如示例所示,可以将a中的myMethod变量更改为指向另一个对象,但是由于此变量是按值传递的,因此更改不会在main中发生。相当于, A(2)又新建了一个对象指向了一个新的内存地址用final a接收,这个a相当于这个函数的局部变量, 跟外部的a地址断开了联系。因为final修饰的变量只能赋值一次, 这样印证了main函数里的a跟myMethod函数里的替换后的a不是同一个地址了。

总结

  • 在 Dart 中,参数传递的方式是值传递(pass by value)。将一个变量作为参数传递给函数时,实际上是将该变量的值复制给了函数的参数。因此,函数内部对参数值的修改不会影响到原始变量。
  • 如果参数传递的是一个引用类型(如 List、Map、Object 等),虽然传递的是引用的副本,但是实际上引用的对象是同一个。这意味着你可以通过引用修改对象的属性或内容,这样会影响到原始对象。
  • 在 Dart 中,基本数据类型的参数传递是值传递,而引用类型的参数传递是将引用的副本传递给函数,但是仍然操作的是同一个对象。

参考资料

引用传递、值传递示例

Why Dart is acting as pass by reference?