Dart语法基础_变量

前言

在前面一篇文章中,我”囫囵吞枣“的介绍了一下Dart中的一些特性,在接下来的文章中我会仔细的介绍,Dart语言中的一些细节,主要内容来源还是官方文档,有兴趣的朋友也可以直接去查看官方文档,本篇主要介绍Dart变量相关的一些知识。

再谈变量

虽然在前面已经介绍过怎么声明和使用变量,但是关于Dart中的变量,还有很多细节没有讲,接下来我会分为四个板块来介绍变量:

  1. null safety,这个词语我们在前面已经多次提到,本篇会详细介绍一下。
  2. 默认值,看看显示指定类型,不给初始值的变量里面到底装的啥?
  3. late关键字,懒初始化变量。
  4. finalconst关键字,使用这两个关键字怎么定义常量,以及他们两定义常量到底有啥区别?

首先来回顾一下上篇文章关于变量部分的内容,上篇文章我介绍了关于变量的两种定义方式,以及nullable类型的变量怎么定义,还是比较简单,写一段代码展示一下应该就明白了:

void main(List<String> args){
    //定义一个 non-nullable类型的变量name
    String name="Devil";
    //使用Dart的类型推断定义变量
    var age=18;
    //定义一个nullable类型的变量,出生日期都能为空啊?从石头缝里蹦出来的?
    DateTime? birthday;
}

回顾完后,我们接着看后面变量的内容。

变量引用

在官网的介绍中,有这么一句话Variables store references,所以我们可以知道,在Dart中,所有变量存储的都是引用,因为基本所有类型都是派生自Object,所以我们在使用Dart中的变量时,要明白这一点。但是这个引用和其他语言的引用是有一定区别的,因为在Dart中引用指的是变量引用,而其他语言中是指某个类型是引用类型

在Dart中,引用分为可变引用和不可变引用(暂时这么称呼它,在官网没有看到相关的名词,如果有朋友知道请提醒作者更改)。给出一个示例介绍可变引用和不可变引用:

var a=["A","B"];
var b = a;
print(a); // [A,B]
print(b); // [A,B]

image-20230930184009146

以上代码,a和b都指向同一个对象,打印出来的结果都是[A,B],但是一旦对其中某个变量进行修改:

var a=["A","B"];
var b = a;
a=["C"];
print(a); //[C]
print(b); //[A,B]

image-20230930184038931

可以看到,并没有修改b的值,b还是指向原来的对象(在大多数语言中,应该都是这样的结果,但是在JavaScript中,就不会是这种结果,JS中b的值也会跟随a的修改而修改,所以在这里拿出来说一下),我们再看另一组代码:

var a=["A","B"];
var b = a;
a.clear();
a.add("C");
print(a); //[C]
print(b); //[C]

image-20230930184310868

可以看到,b的值也随着a的值的修改而修改了。

所以我们在这里可以得出一个简单的结论,在Dart中所有变量存储的都是引用,直接对变量进行赋值,其实更改的是变量引用的指向,所以就算两个变量指向同一个对象,那么其中一个变量更改引用的指向,当然不会影响到另外一个变量。但是,使用两个变量所指向的对象的方法进行修改,那么对两个变量进行访问的时候,值都会受到影响。

根据我们上面说的可变引用和不可变引用的说法,那么可变引用都会提供可以修改对象内部值的方法,使用该方法对对象进行修改,才能起到作用,比如:List,Map,Set等等,都提供了修改内部值的方法,那么指向这些类型的引用就是可变引用,而不可变引用则不提供修改对象的方法,比如:Stringboolint等等,这些没有提供修改方法的就是不可变引用,只能使用赋值来改变引用的指向。

Dart使用这种巧妙的方法,统一了变量的类型,都是引用类型,不分什么值类型。并且也限制了对基础类型,如Stirng,bool等的更改。

注意:

在Dart中,如果要更改某个变量所指对象的值,请使用该对象提供的方法(method)进行更改,不然你的更改是无效的。

Null safety

在Dart高版本中(Dart3),强制执行了完全的null safety机制,那么什么是null safety机制?

如果学习过C/C++,我们可以知道,对于一个空指针,最不安全的行为,就是对其进行解引用(dereference),所以null safety机制,主要就是防止该事件的发生,防止你误操作,解引用了一个空指针。

在Dart没有引入null safety的时候,你如果使用一个nullable的对象,去调用它的方法,那么会造成空指针解引用错误,导致程序崩溃,例如:

int? v;
v.abs();

在引入null safety之后,你可以在compile time或者edit time发现该错误,IDE或者编译器会直接给你一个报错,你不能使用一个未初始化的nullable 变量。

在引入null safety之后出现了三个关键的变化(官网上这么说的):

  1. 当你给一个变量、参数、或者其它相关组件明确指定了类型,那么你可以控制它是否可以允许为空。(就是使用Type?语法)
  2. 在你使用一个变量之前,你必须初始化它。nullable的变量默认值为null。Dart不会为non-nullable类型的变量设置一个初始值,它强制你为non-nullable类型初始化。Dart也不允许你监听或者观察一个没有初始化的值。还有就是当一个方法的receiver(熟悉Go语言的朋友肯定不陌生这个词)可以为null时,如果receivernull,那么你无法使用这个receiver调用方法或者属性。
  3. 当一个表达式为nullable类型时,无法使用该表达式访问属性或者方法。

null safety 还有两个例外的函数 就是 hashCode和toString,这两个函数在receiver为null时也可以访问。

综上所述:

null safety,就是帮你在edit-time或者compile time消除潜在的空指针解引用runtime errors

默认值(Default value)

在Dart中,当一个类型是nullable时,它会被初始化为null,不论是:String,int,还是其他什么类型,只要被标记为nullable,在没有显示初始化时,那么就会被初始化为null

但是对于non-nullable的变量,由于null safety的限制,你在使用该变量之前,必须对它进行初始化。所以也就没有默认值一说了。

Late

late关键字主要用在两个地方:

  • 声明一个在声明位置之后初始化的non-nullable 变量
  • 懒初始化一个变量

使用late关键字,可以将一个变量标记为,稍后初始化。如果你确定某个变量在使用前会初始化,但是Dart不同意,给出一个报错或者警告,此时你就可以在变量前加上late关键字,来告诉Dart你会在稍后初始化它,示例如下:

late String description;

void main() {
  description = 'Feijoada!';
  print(description);
}

所以,如果使用了late关键字,那么就需要你自己去保障该变量会初始化,如果初始化失败,那么在运行时使用该变量的时候,会造成错误,可能会导致程序崩溃。

使用late也会提供一些性能上的优势,如果你在声明的时候直接初始化一个使用late声明的变量,那么在后续代码中如果没有使用该变量,不会带来额外的开销,因为late声明的变量,只有在第一次使用时才会被初始化。

late String temperature = readThermometer();

final和const

这两个关键字都是用来定义常量的,但是有所区别,final修饰的变量只能被赋值一次(可以在任何地方赋值,但是只能赋值一次),const修饰的变量会在编译时替换为常量。(const变量隐式就是final的)

final name="Devil";
final int age=18;
const baz=[];

如果要在类中使用const定义常量,那么需要使用static const variable来定义。

class MyClass{
    static const test=10;
}

常量还有如下几种定义方式:

var foo = const [];
final bar = const [];
const baz = []; // 等价于 `const []`

以上代码中 foo,没有使用 final和const 进行修饰,所以可以对foo的变量指向进行修改。

foo = [1, 2, 3];  //这种修改是不会报错的,因为foo没有被final和const修改
baz = [100];      //这种修改是会报错的,因为baz被const修饰了

以上就是作者对变量这部分简单介绍,如果有哪些地方不对,或者错误,请读者指出,作者会及时修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值