当我在学习dart的基础知识时,它提到dart是100%纯面向对象编程语言事件基元类型,如int,double是对象,并作为引用而不是值传递。
void main() {
double number = 44;
print('before $number');
changeNumber(number); // with this it does not print 45
// number++; with this it does print 45;
print('after $number');
}
void changeNumber(double number) => number++;
输出:
45岁以前
44岁以后
我期待人们解释我,如果int是一个对象,为什么其他函数不能改变它时传递,我知道dart通过值传递数字,但为什么它这样做
2条答案
按热度按时间gdrx4gfi1#
我希望人们解释我,如果int是一个对象,为什么其他函数在传递时不能改变它,我知道dart通过值传递数值。
正如mousetail在他们的评论中提到的,仅仅因为某个东西是一个对象,并不意味着对象的状态是可变的。Dart中的很多类都是为了创建不可变的对象而设计的,任何类型的变化都会导致另一个对象示例。
例如,
int
、double
和String
都是类的所有类型,其中这些类的对象是不可变的。在示例中,
number++
操作意味着number = number + 1
。这里定义了number
(double
)上的+
运算符,以获取1
,并返回一个新的double
对象,其中我们得到了将1
添加到number
的结果。由于我们没有操作
number
对象本身,所以对该对象的任何引用仍然会观察到number
的原始值。然而,我们确实将新的
double
示例重新分配给变量number
。这就是为什么在main
中工作的原因,因为变量是一个局部变量,你可以更改它引用的值。但是函数的参数作为引用的副本发送。因此,如果我们操纵对象的内部状态,发送到函数,那么这些变化对函数的调用者来说是可见的。但是如果我们将引用/参数更改为指向其他对象,那么调用者将看不到此更改。
由于
double
是一个不可变的对象,我们保证这个对象的任何更改都会导致另一个对象示例,因此我们需要更改对这个新对象的引用,以便观察到更改。由于函数的参数是引用的副本,因此对该副本引用的任何更改都不能在函数本身之外观察到。ltqd579y2#
甚至像int,double这样的基本类型也是对象,并且作为引用而不是值传递。
Dart并没有真正的引用(或指针),所以这句话对理解发生了什么没有多大帮助。
函数形参可以看作是调用者的实参被赋给的局部变量。新变量得到的值与原始变量“相同”(但它不是C语言中的引用-您不能传递引用并让其他人更改它指向的内容)。
在您的示例中,当您调用
changeNumber(number)
时,可以将其替换为:这就是所谓的“内联”,编译器实际上可以自动完成。无论如何,你基本上改变了
$number
变量的值,而不是原来的number
,因为在被调用函数的作用域内是不可访问的(在上面的例子中是这样的,但编译器会阻止你在现实中使用它)。希望你明白,
number++
并没有改变number
变量的“内部”,它只是返回一个新的数字,然后分配给同一个变量。换句话说,这就是实际发生的事情:正如其他人指出的那样,面向对象与此无关,因为在OOP中,对象被允许是完全不变的,而Dart中的数字是不变的。您可以在Dart 3中轻松创建不可变对象,例如:
你可以添加方法来将一个
ComplexNumber
添加到另一个ComplexNumber
中,但是你需要返回一个新的方法,而不是改变当前的方法来保持它的不可变:你可以让
ComplexNumber
变,但即使在现代的OOP中,人们通常更倾向于让对象不可变,因为这有助于程序的推理能力极大地提高(这可能会牺牲性能,因为改变某些东西比在每次改变时分配新对象更有效率)。