同时搞定Android和iOS的Dart语言(2):变量与常量
1. 定义和使用变量
尽管Dart是静态语言,但仍然拥有动态特性。所以定义变量也有如下2种方式。
使用数据类型定义变量
使用var定义变量
在Dart语言中,数据类型放在变量前面,格式如下:
数据类型 变量名;
在Dart语言中,每条语句后面必须跟分号(;),所以在定义变量时后面也要加分号。如下面的代码定义了一个整数类型的变量和一个字符串类型的变量。
int num; // 整数类型的变量
String s; // 字符串类型的变量
在定义变量时可以同时为变量赋值,也称为初始化,所以可以用下面的代码为num和s赋值。
int num = 20;
String s = "hello world";
如果在定义变量时指定了数据类型,那么就意味着变量的数据类型不可以改变,例如,上面代码中已经将num变量定义为int类型,那么num就永远是int类型,不可以为该变量赋其他类型的值。
由于Dart语言中一切皆为对象,所以如果在定义变量时没有为其初始化,那么变量的默认值就是null。
另外一种定义变量的方法是使用var关键字,代码如下:
var num = 20; // num被自动识别为int类型的变量
var value; // 由于value在定义时没有被初始化,所以value的数据类型是dynamic
上面两行代码分别使用var定义了两个变量,但这两个变量是有区别的。num变量由于在定义时已经初始化了,所以num的数据类型会根据初始化的值自动识别,很显然,20属于int类型的值,所以num变量的数据类型就是int,而且与直接指定变量的数据类型一样,num变量的数据类型将永久固定,后期是不可以改变的。但value就不同了。由于在定义value变量是没有为其初始化,也没有指定数据类型,所以value的数据类型就被识别为dynamic。这是Dart语言中的一种特殊数据类型,有了dynmaic,Dart就可以很容易动态化。如果Dart编译器遇到dynamic数据类型的变量,就不会对该变量进行任何类型检测,相当于在JavaScript中使用变量一样。不过如果调用了变量中不存在的成员(如属性、方法等),在运行时会抛出异常。但dynamic提供了解决方案来避免这种异常,关于dynamic的详细用法,在后面的章节会深入介绍。
综上所述,在Dart语言中,如果为变量指定了数据类型,那么变量就是静态的,变量的数据类型永远不可以改变。如果变量的数据类型是dynamic,变量就是动态的。可以为该变量赋任何值。让变量是静态类型和动态类型分别由如下2种方式。
(1)静态类型的变量
(1)显式指定变量的数据类型,如int num;
(2)使用var定义变量,但在定义时初始化了变量,并且初始化变量的表达式不是dynamic类型。如var value = 20;
(2)动态类型的变量
使用var定义变量,而且在定义时未初始化变量。即使在后面为变量赋了值,该变量仍然是dynamic类型的变量,如var value;
直接使用dynamic类型定义变量,如dynamic value;
本例演示了各种定义和使用变量的方式。
void main() {
var name = "Bill"; // String类型变量
var value1 = 20; // int类型变量
int value2 = 30; // int类型变量
print(name); // 输出Bill
print(value1 + value2); // 输出50
// 在Dart中一切都是对象,如果未初始化变量,变量的默认值就是null
var value; // dynamic类型变量
int value3; // int类型变量
print(value); // 输出null
print(value3); // 输出null
String s;
// 条件为true
if(s == null) {
print("NULL");
}
}
运行结果如图1所示。
图1定义和使用变量
2. 定义和使用常量
常量的定义方式与变量类似,只是需要使用const或final来定义常量。这两个关键字相当于var对于变量的作用。下面是定义常量的基本方法。
final username = '李宁';
const value = 1234;
在上面的代码中,username和value是两个常量,这两个常量都没有指定数据类型,不过由于Dart语言要求常量必须在定义时初始化,所以所有定义的常量右侧都会有一个初始化表达式,Dart编译器会利用这个初始化表达式自动识别常量的数据类型。上面的例子中,username被识别为String类型,value被识别为int类型。
在定义常量时,也可以显式地为其指定数据类型,代码如下:
final String username = '李宁';
const int value = 1234;
常量只能在定义时被初始化一次,不能在使用的过程中赋值,所以下面的代码是无法编译通过的。
username = '小明'; // 无法给常量赋值,会出现编译错误
value = 4321; // 无法给常量赋值,会出现编译错误
那么可能有的读者会问,为什么定义常量要提供两个关键字(const和final)呢?其实用这两个关键字定义常量是有一定区别的。const是编译时常量,而final是运行时常量。下面解释一下什么是编译时常量,什么是运行时常量。
编译时常量:在Dart编译器在编译时会自动计算的常量,也就是说,不管常量的初始化时是一个值,还是一个表达式,Dart编译器都会将这个表达式计算成一个值。换句话说,这种常量不管初始化表达式是什么,最终在内存中都是一个值。所以使用这种常量的效率特别高。
运行时常量:这种常量与变量类似,都会在每次使用常量时现技术常量初始化表达式的值,所以使用这种变量的效率较低。
既然编译时常量在编译代码时会自动计算初始化表达式的值,那么就意味着初始化表达式中的每一个部分都必须在编译时可以获得具体的值。这就要求初始化表达式只能由值或其他编译时常量组成,不能由变量、运行时常量、函数组成。因为这些元素的值只有在程序运行时才可以获得,而编译时程序还没有运行,所以编译时常量的初始化表达式不能由这些元素组成。
运行时常量的初始化表达式与变量的初始化表达式类似。
const和final的用法见下面的代码。
const m = 20; // 编译时常量
const n = m + 30; // 编译时常量
final k = 40; // 运行时常量
const w = k + 20; // 编译错误,因为编译时常量的初始化表达式只能由值和编译时常量组成
3. 常量列表和列表常量
常量同样也可以用来定义列表。列表是Dart语言的内建数据类型,关于列表的详细用法,会在后面的章节深入介绍。本节只介绍使用final和const定义常量列表和列表常量。那么这两个列表有什么区别呢?
常量列表:指列表中的每一个元素都是常量,但列表本身可能是一个常量,也可能是一个变量。如果列表本身是一个变量,而列表元素都是常量,那么就意味着不能修改列表的每一个元素,但可以再次为列表变量赋值。
列表常量:指列表本身是一个常量。对于这样的常量,列表中每一个元素同样也是一个常量。对于这种列表,列表本身与列表中的元素都不可以改变。
在定义常量列表时,可以在列表初始化值前面加const(不能使用final),也可以不加。在定义列表常量时,可以使用const,也可以使用final。
本例演示了常量的定义和使用方法,以及常量列表和列表常量的定义与使用方法。
void main() {
final username = '李宁';
const password = '1234';
// username = "abc"; // 编译错误,不能为常量赋值
// password = "1234"; // 编译错误,不能为常量赋值
const n = 20;
final x1 = n *2 + 20;
const x2 = n * 2 + 20; // 自动计算,x2实际上存储的是60
const x3 = x2 * 2;
print(x2);
print(x3);
var values1 = const [1,2,3]; // 定义一个常量列表
print(values1);
values1 = [5,6,7]; // 列表本身是变量,所以可以重新设置列表的值
print(values1[1]);
// values[1] = 4; // 不会有编译错误,但会抛出运行时异常
final values2 = const["a","b"]; // 定义列表常量
// values2 = ["b","c"]; // 编译错误
// values2[1] = "x"; // 运行时错误
const values3 = [5,6]; // 定义一个列表常量
// values3[1] = 4; // 运行时错误
}
运行结果如图2所示。
图2常量与列表
往期回顾:
同时搞定Android和iOS的Dart语言(1):Dart初探
本文分享自微信公众号 - 极客起源(geekculture)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
谁说Cat不能做链路跟踪的,给我站出来
背景 链路跟踪,我们有很多可选项。常见的有 zipkin,pinpoint,skywalking,jaeger 等。 基本上都是根据谷歌的《Dapper 大规模分布式系统的跟踪系统》这篇论文发展出来的。 今天讲下 Cat 里的链路跟踪要如何来实现,没用过 Cat 的同学可以查看我的这篇文章 《熬夜之作:一文带你了解 Cat 分布式监控》进行了解。 在 Cat 中可以很方便的看到每个请求的总耗时以及业务操作,数据库操作的耗时情况。对于服务之间的调用也可以通过埋点的方式进行监控。 如下图,可以看出请求内发起了一次 RPC 的调用,callRPC 开头的那条记录。耗时 11ms, 但是这个 RPC 服务内部耗时花在哪里了,在这边不能直接查看,只能去另一个服务中查看,不是很方便。 图片 详细的我画了一张图说明下现在的问题: 从上图可以看出,一个请求经过了多个服务,每个服务中对远程调用或者本地调用都有埋点,这样就能监控到调用的异常和性能指标。 下面一部分是在 Cat 中我们去查看这些指标的场景,Cat 中的数据展示是以项目维度来展示的,所以每个服务都有自己的监控数据。 如果我想要知道刚刚那次请求...
- 下一篇
Elasticsearch从入门到放弃:瞎说Mapping
前面我们聊了 Elasticsearch 的索引、搜索和分词器,今天再来聊另一个基础内容—— Mapping。 Mapping 在 Elasticsearch 中的地位相当于关系型数据库中的 schema,它可以用来定义索引中字段的名字、定义字段的数据类型,还可以用来做一些字段的配置。从 Elasticsearch 7.0开始,Mapping 中不在乎需要定义 type 信息了,具体原因可以看官方的解释。 字段的数据类型 我们刚刚提到 Mapping 中可以定义字段的数据类型,这可能是 Mapping 最常用的功能了,所以我们先来看看 Elasticsearch 都支持哪些数据类型。 简单类型:text、keyword、date、long、double、boolean、ip 复杂类型:对象类型、嵌套类型 特殊类型:用于描述地理位置的 geo_point、geo_shape Elasticsearch 支持的数据类型远不止这些,由于篇幅原因,这里就不一一列举了。我找几个工作中常见的来介绍一下。 首先就是字符串了,Elasticsearch 中的字符串有 text 和 keyword 两种...
相关文章
文章评论
共有0条评论来说两句吧...