Dart语言之常用数据类型

目录

前言

一、Dart概述

二、Dart常用数据类型

2.1、Dart知识体系

2.2、数字类型(num、int和double)

2.3、字符串(String)

2.4、布尔

2.5、集合之List

2.6、集合之Map

2.7、dynamic、var和Object的区别


前言

又有一段时间没有写东西了,很长时间不写,表明了两个点,一个是说明了自己的惰性,另一个就是说明了自己这段时间没有任何的提升,所以下午的时候我就在想晚上一定得写点东西,要么做技术复盘,要么写点新东西,然后就一直酝酿晚上回去该写点什么?最终决定写点基础的。因为现在市面上有些公司开始招聘Flutter开发相关的技术人员了,结合我之前写过的一篇《Flutter入门:开发环境与开发工具的准备》,那么当你环境准备好之后那肯定是要攻克开发语言了,所以接下来的几篇文章我会在我的Dart专栏里面跟大家分享一些Dart语言的基础知识,有了这些基础知识,你就可以去好好研究Flutter SDK了。

一、Dart概述

针对Dart语言的特点做以下几点说明:

1、Dart2.0:强类型的静态类型(编译时已知变量的类型)的语言,和Java、C#等比较类似,所有类型的检查都可以通过编译器来完成;

2、面向对象(OOP):这个特点类似的语言比较多:有Python、C++、Objective-C、Java、Kotlin、Swift、C#等等;

3、JIT&AOT:JIT(Just in Time)优点:即时编译,开发期间更快编译,更快的重载;缺点:在运行时将代码编译成机器码,给用户最直接的感受就是慢;AOT(Ahead Of Time)事前编译,release期间更快更流畅,典型的例子就是C和C++,它能够直接编译机器码即二进制代码,所以它的加载和执行速度是非常快的。你会发现在开发期间安装Flutter的时候会有一些卡顿,但是在release就是发布之后会变好,这种模式使得APP在发布之后能够以更快的速度运行。

二、Dart常用数据类型

2.1、Dart知识体系

这里用一张思维导图来展示Dart的整个知识体系

2.2、数字类型(num、int和double)

1、num:

Dart数字类型的父类,它既接受浮点类型,也接受整数类型。

num num1 = -1.0; //num是数字类型的父类
num num2 = 2; //num是数字类型的父类

2、int、double

num有两个子类,一个是int,一个是double,int类型只能接收整数,double类型是双精度

int int1 = 3; //子类一 int类型 只能接收整数
double d1 = 2.22; //子类二 双精度

在dart中数字类型如何进行类型转换呢?可以通过toInt()、toDouble等方法,还有一些常用的api,比如abs()、round()等等,我们通过一段代码来看一下它的运行结果:

///数字类型
  void _numType() {
    num num1 = -1.0; //num是数字类型的父类
    num num2 = 2; //num是数字类型的父类
    int int1 = 3; //子类一 int类型 只能接收整数
    double d1 = 2.22; //子类二 双精度
    print("num:$num1 num2:$num2 int1:$int1 d1:$d1");
    print(num1.abs()); //求绝对值
    print(num1.toInt()); //转换成int类型
    print(num1.toDouble()); //转成Double类型
    print(num1.toString()); //转成字符串
  }

运行结果如下:

2.3、字符串(String)

在dart中定义字符串可以用单引号也可以用双引号,一行可以定义一个字符串,也可以定义多个字符串,中间用逗号隔开:

String str1 = '字符串', str2 = "双引号字符串"; //字符串的定义

在dart中如何进行字符串拼接呢?答案很简单,可以直接使用加号“+”拼接,当然还有另外一种方法,在上面数字类型的讲解中也有使用到,我们可以使用"$"加上变量名去引用一个变量,这个变量可以是数字类型当然也可以是字符串类型:

String str3 = 'str1:$str1 str2:$str2'; //字符串拼接
String str4 = 'str1:' + str1 + "str2:" + str2; //字符串拼接

接着来看dart中字符串有哪些常用的api呢?字符串中的方法有很多,这里只介绍几种常用的,其它的方法大家可以自行学习,学习的方法也很简单,将鼠标移至字符串操作中的某个方法上,比如.substring()上面,然后Windows下按住ctrl键,Mac下按住command键,点进去就到了String这个类的源码当中,这里面有所有字符串操作的方法,每个方法都有对应的注释说明,看不懂英文的网上找个翻译软件跟着学习就行,下面介绍几种常用的:

//字符串截取,包含开始索引,不包含结束索引
String substring(int startIndex, [int endIndex]);
//获取一个字符串在另一个字符串中的位置
int indexOf(Pattern pattern, [int start]);
//判断一个字符串是否是以某种匹配规则开始的
bool startsWith(Pattern pattern, [int index = 0]);
//判断一个字符串是否包含某个匹配项
bool contains(Pattern other, [int startIndex = 0]);
//将某个字符串按照某种匹配规则进行拆分,并返回子字符串列表
List<String> split(Pattern pattern);
//将所有与from匹配的子字符串替换为replace,from和replace为方法的入参
String replaceAll(Pattern from, String replace);

其实这些方法和我们在java中使用的都是差不多的,我们再来写个方法进行实际查看一下结果,加深理解:

///字符串操作
  _stringType() {
    //字符串常用方法
    String str5 = '常用数据类型,请看控制台输出';
    print(str5.substring(1, 5)); //字符串截取
    print(str5.indexOf('请看'));
    print(str5.startsWith('常')); //是否以xx开始的
    print(str5.contains("数据"));
    print(str5.split(","));
    print(str5.replaceAll("类型","安奇"));
  }

结果如下:

2.4、布尔

Dart是强bool类型检查,只有bool类型的值是true,才被认为是true,对于bool类型来说,实际开发中用的比较多的就是逻辑运算,常用的也就是逻辑与和逻辑或的运算,这一块比较简单,写个方法验证一下即可:

///布尔类型,Dart是强bool类型检查,只有bool类型的值为true,才被认为是true
  _boolType() {
    bool success = true, fail = false;
    print(success);
    print(fail);
    print(success || fail); //true
    print(success && fail); //false
  }

结果如下:

2.5、集合之List

1、List集合的初始化

在Dart中定义集合使用List关键字,List<E>表明集合是个泛型,这里可以传入任何数据类型。

List集合可以使用“[]”进行初始化,例如:List list = [1,2,'测试']; 这种形式,这里没使用泛型所以中括号里面添加元素时既可以传入数字也可以传入字符串,如果需要指定泛型类型,例如:List<int> list1 = []; 这种形式下,添加元素的时候只能添加int类型的数据。如果我们把list集合直接赋值给list1集合会怎么样呢?可以思考一下,也就是 list1 = list; 这样,答案是会报错,如下所示:

原因是什么呢?是因为list这个集合我们并没有给它指定泛型,在dart里面有一个动态数据类型,也就是说list集合是动态数据类型的集合,我们将一个动态数据类型赋值给一个确定类型的集合时会报错,错误是动态类型集合不是确定类型集合的子类型,这一点需要注意。

除了上面的这种[]里面直接添加元素的方式初始化以外,我们还可以通过集合的add()或者addAll()方法进行初始化集合的操作,比如下面的代码:

List list = [1, 2, 3, '集合']; //初始化添加元素
List list3 = [];
list3.add('list3'); //通过add方法添加元素
list3.addAll(list);
print(list3);

结果就是:

2、常用方法

这里只介绍一个集合中常用到的方法——集合的生成函数,其它的函数大家点到源码里面自行学习吧:

//创建一个具有length位置的列表,并用创建的值填充它,范围为0——length-1的每个索引升序排列
List.generate(int length, E generator(int index));

什么意思呢?举个栗子:

List list4 = List.generate(3, (index) => index * 3);
print(list4);

结果如下:

这里对照着注释我们来做个说明:函数体中第一个参数length传入的值为3,说明我们生成的这个集合的长度为3,第二个参数实质上是一个方法体,“=>”符号在这里我们可以当成是一个箭头表达式,并且是方法体只包含一个表达式时才能这样使用,所以这里的第二个参数其实就是一个有返回值的函数,函数体是index(索引)乘以3,将得到的值进行返回,这个表达式也就等同于return index*3;的值,那么这样就很简单了,在函数说明的时候我们说了范围是0 - length-1的每个索引,那这里的索引值也就是0,1,2,然后将每个索引值乘以3得到的值依次为0,3,6,这样就得到了我们的集合[0,3,6]。

除了集合的生成函数外,集合还有很多经常用到的方法,我就不再进行详细的说明了,因为这些方法我们在Java中也经常使用,所以大家肯定是见其面知其意,下面大致列举几个:

//删除集合中的某个元素
bool remove(Object value);
//从集合中删除指定位置处的元素
E removeAt(int index);
//在集合的指定位置处插入某个对象
void insert(int index, E element);
//截取指定范围内的集合元素并返回成一个新的集合,入参的索引范围同样是包含左边不包含右边
List<E> sublist(int start, [int end]);
//查找集合中某个元素第一次出现的位置索引
int indexOf(E element, [int start = 0]);

3、List集合的遍历

这里介绍集合的常用的几种遍历方式:

第一种:没有语言之分的for循环方式:

for (int i = 0; i < list.length; i++) {
    print(list[i]);
}

第二种:for...in...,同样是for,但是表达式内部我们做一点修改,使用var关键字定义一个变量,然后使用in关键字在集合中进行遍历:

for (var o in list) {
   print(o);
}

第三种:forEach()循环,将函数应用于集合的每个元素,括号内传入的为集合的元素:

list.forEach((val) {
    print(val);
});

三种遍历方式得到的结果肯定都是一样的,如下所示:

2.6、集合之Map

1、Map集合的初始化

Map是将key和value相关联的对象,key和value都可以是任意类型的对象,并且key是唯一的,如果key重复,后面添加的key会替换前面的内容。

定义Map使用大括号“{}”,因为map是key-value的形式,所以添加元素的时候也是以键值对的形式进行添加,键和值中间使用冒号“:”进行分隔,比如:'a':'小明' 的形式,元素和元素之间使用逗号“,”分隔。除了这种初始化的方式外,我们还可以使用另外一种更加灵活的初始化的方式,首先可以初始化一个空的map,比如 Map map = {};  然后我们往这个空的map里面添加元素,我们使用中括号“[]”,中括号里面跟上元素的key,然后使用等号“=”连接,在等号右边为其赋值,比如 map['a']='小明';

这里简单的写个例子,这样看起来更加直观:

///Map初始化
Map names = {'xiaoming': '小明', "xiaohong": "小红"};
print(names);
Map ages = {};
ages['xiaoming'] = 12;
ages['xiaohong'] = 18;
print(ages);

结果如下:

2、常用api

//根据集合中的某个key,删除相关联的元素
V remove(Object key);
//判断集合中是否包含指定的key
bool containsKey(Object key);

3、Map的遍历

第一种:forEach

它的里面需要一个回调函数,回调函数里面会输出我们的key和value,代码也很简单:

///Map遍历方式
ages.forEach((k, v) {
    print('$k,$v');
});

通过$引用key或者value,我们就可以根据需要去使用它的键或者值了。

第二种:map()方法

我们可以调用Map集合的map()方法遍历生成一个新的map集合,这个方法接收一个回调函数,入参为key、value,函数内部必须接受一个return,也就是说它会返回一个新的map,这里通过MapEntry来返回之前Map里面每一项的元素,我这里将原map的key和value进行颠倒,那么就可以得到一个相反的集合,来看一下代码:

Map ages2 = ages.map((k, v) {
    return MapEntry(v, k);
});
print(ages2);

结果如下:

第三种:for循环

首先循环遍历map集合中所有的key,可以通过map.keys获取,它返回的是一个所有key值的数组(同样的也有map.values),然后我们就可以通过map[key]获取集合中的每一个元素了,代码如下:

for (var key in ages.keys) {
    print('$key , ${ages[key]}');
}

这里需要注意,我们使用字符串拼接的时候,如果需要调用方法的时候,就像上面ages[key]这样的时候,必须在$后面跟上大括号这种方式进行调用,结果如下:

2.7、dynamic、var和Object的区别

1、dynamic 

先上一段代码,看了之后再来说点具体的:

dynamic x = 'jarchie';
print(x.runtimeType);
print(x);
//x.foo(); //编译不会报错,运行时才会发现x并无此方法,会报错
x = 123;
print(x.runtimeType);
print(x);

结果如下:

它是dart里面的动态数据类型,我们使用这个关键字定义了一个变量,打印了它的运行时,并且打印了这个变量值,通过结果可以看出它的运行时是一个String,也就是说动态数据类型在编译时不知道你是什么类型,然后在运行的时候根据你后面的值去推测你是什么类型,它的好处是通过它可以定义任何的数据类型,缺点是它可以使dart的语法检查失效,为什么会失效呢?因为语法检查是静态语法检查,也就是在不运行代码的时候的语法检查,比如上面我注释掉的那行代码,编译的时候不会报错,当你运行的时候会报错:Class 'String' has no instance method 'foo',意思就是说这个变量并没有foo()这个方法,所以我们最好不要直接去使用它,为了避免带来一些不必要的错误。我们在代码中还更改了它的值为整型数据123,此时它的运行时也就变成了int类型。

2、var

var是一个关键字,不必关心它的类型是什么,系统也会自动推断它的数据类型,它和动态数据类型最大的区别是,当它的类型被确定之后,它是不允许修改的,就是说编译期语法检查都过不去,举个栗子:

    var a = "jarchie";
    print(a.runtimeType);
    print(a);
//    a=123; //下方报红,语法检查时有错误
    a = "anqi";

变量a的数据类型是已经确定为字符串了,不能再赋值为整型。

3、Object

Object是Dart里对象的基类,当我们将一个变量定义为Object类型的时候,系统就会认为这个变量就是Object类型,对于Object类型它里面有一些定义的方法,此时这个变量就可以调用相应的方法,它和动态数据类型最大的区别就是你不可以调用Object不存在的方法,编译器语法检查也是过不去的,因为它的数据类型也是确定的。

好了,本篇Dart的常用数据类型部分就写到这里,下一篇准备写Dart的面向对象,我也是希望自己能有时间去尽快的整理出来,实在抽不开身我也是没有办法啊,我太难了!要学的东西太多,学不动了。。。。。。大家加油,我先洗洗睡了!

发布了48 篇原创文章 · 获赞 47 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/JArchie520/article/details/103375667