Flutter 之 Dart语言基础详解 上篇
经过了一个星期的React Native的学习和了解,感觉还是Flutter的优势会更高一些,而且从学习成本来说感觉做安卓的同学学习flutter会相对低一点,门槛会低很多。当然dart的基础笔者还是从其他朋友的资料总结而来,这里我尽可能的说的清楚一些!
文章纯干货!!!!!文末有福利!!!
首先是关键字(56个)
| 关键字 |
| abstract | do | import | super | as | dynamic | in | switch | assert | else | interface | sync* | enum | implements | is | this | async* | export | library | throw | await | external | mixin | true | break | extends | new | try | case | factory | null | typedef | catch | false | operator | var | class | final | part | void | const | finally rethrow | while | continue | for | return | with | covariant | get | set | yield* | default | if | static | deferred |
从上面的关键字里面可以看出和Java中的关键字还是有很多一样的,含义也是如此。
变量的声明
- var
- dynamic
- Objec
首先声明一个变量,变量的类型可以改变:
var name;
name = 'tom';
name = 123;
dynamic name;
name = 'tom';
name = 123;
Object name;
name = 'tom';
name = 123;
这里是不会报错的,说明变量的类型是可以改变的,并且都是可以print出来。
声明一个初始化的变量,变量类型不能再更改:
var name = 'tom';
name = 123;//这里是不对的,编译器会报错
这里声明一个name被发现时String类型的之后,就不能转变其他的类型了
但是:
dynamic 和 Object 声明的变量初始化后,变量的类型仍可改变:
dynamic name = 'tom';
name = 123;
Object name = 'tom';
name = 123;
这里dynamic和Object声明的类型是可以改变的。
使用确定类型显示声明变量,变量的类型不能再改变:
String name = 'tom';
name = 123;//这里已经定义name是Stiing类型的,就不能更改为int类型
默认值
看到这里我们想了解了,如果声明一个变量,没有初始值的时候他的默认值是什么呢?
dart里面的默认值都是null,一切皆对象,对象的默认值是null。
ar name;
assert(name == null);
print("assert pass");//可以正常打印
这里我们发现此处的断言是可以是真的,程序不会崩溃,说明默认值是null。
final 和 const
这两个关键字很重要
首先被这两个关键字修饰的变量,变量类型是可以省略的:
const age = 1;
final sex = '男';
被其修饰的变量无法更改其值,并且声明出来之后必须要进行初始化,相信学过Java的同学肯定对final这个关键字很熟悉了吧
var varList = const [1, 2, 3];
final finalList = const [1, 2, 3];
const constList = [1, 2, 3];
print([varList, finalList, constList]);
varList = [1];//这里允许更改
// constList = [1];//这里不允许更改
// finalList = [1];
可以更改非 final,非 const 变量的值,即使它曾经具有 const 值。
final List ls = [1, 2, 3];
ls[2] = 444;
print(ls);
const List cLs = [4, 5, 6];
cLs[1] = 4;
print("\n");
print(cLs);
这里同样是更改集合中某个元素的数值,final的是没有问题的,const的编译时没问题,但是运行起来会报错:
Unsupported operation: Cannot modify an unmodifiable list
不能更改一个不能修改的集合。
finalList1 = [1, 2, 3];
final finalList2 = [4, 5, 6];
print("\n");
print(identical(finalList1, finalList2)); //identical用于检查两个引用是否指向同一个对象
const constList1 = [1, 2];
const constList2 = [1, 2];
print("\n");
print(identical(constList1, constList2)); //identical用于检查两个引用是否指向同一个对象
这里相同的集合final声明的会在内存中重复创建,const声明的就不会重复创建,上面打印:
![](https://img.haomeiwen.com/i15233518/cc0ffccf492f678f.jpg)
external bool indentical(Object a, Object b);这个方法传入两个引用来检测是否指向同一个对象,返回bool类型。
常量如果是类级别的,必须要使用 static const来修饰:
class C{
static const String a = 'hehe';
//这里只有类级别的常量的时候我们请使用static const来修饰,并且初始化
}
如果去掉static编译就会报错:Only static fields can be declared as const,只有静态字段可以声明为const。
内置类型
Number数值(num,int,double)
首先int和double都是num的子类,用法跟int和double一样,都是可以直接进行运算:
num n1 = 1;
num n2 = 1.0;
print('n1 + n2 = ${n1+n2}');
输出:
n1 + n2 = 2.0
自动识别double类型输出2.0不会丢失精度。
转换
转换这个环节是必不可少的,在Java中我们只int和double、float都是可以进行和String互相转换的,dart中也是可以的:
int i2 = int.parse('1');
print('i2---->{d2}');
int i3 = int.tryParse('1.0');//返回 null
print('i3:${i3}');
输出如下:
![](https://img.haomeiwen.com/i15233518/71a0824526532d05.jpg)
这里细心地同学看到i3为什么输出是null,而不是1或者1.0呢,我们为什么调用tryParse而不用parse呢,试着去解析,如果有问题不会崩溃,个人理解这就是这个方法的真正的目的所在,1.0被识别出是double类型,我们用int去解析并且接受就会导致丢失精度的问题所以不予通过,方法会返回null,但是我们用parse来看看就发现程序崩溃了:
![](https://img.haomeiwen.com/i15233518/9ffffd597e2086f9.jpg)
所以也就很容易理解了。
String 字符串
说道String,Java的同学肯定很熟悉啦,不过dart里面的String是UTF-16编码的,所以我们可以用单引号''或者双引号“”来声明字符串。
String string = 'haha';
String string1 = "hahaha";
都是ok的!
var name = 'HelloWorld';
//可以在字符串中使用表达式:{name}';
//r 前缀可以创建一个 “原始 raw” 字符串
//加了r,转义符号 \n 换行 \t (按一次tab键的水平制表符)不起作用了
var rawNames = r"HelloWorld{names}');
print('rawNames :${rawNames}');
这里我们发现${}表达式可以直接拿去变量值来进行输出,并且在字符串前面加上r只有会发现这个表达式效果失效了,那这也是dart的一个规则吧,可以试一下字符串里面加上 \n、\t等转义字符,会发现这些也都失效了,都被打印了出来!
看看下面代码:
//可以使用三个单引号或者双引号也可以 创建多行字符串对象
var multiLinesString = '''
Java
Android
Flutter''';
print('mutiLinesString:${multiLinesString}');
这里我们发现用了三个‘来声明一个字符串,这样得声明有何意义呢?看一下效果:
![](https://img.haomeiwen.com/i15233518/a35effd67768578a.jpg)
你们会发现竟然跟我们摆放的字符串格式一样,对的,他的含义就是这样!
接下来看一下StringBuffer的使用:
/// StringBuffer
var sb = StringBuffer(); //dart 2 可以省略 new
sb..write('aaa')..write('bbb')..write('ccc');//..级联符实现链式调用
sb.writeAll(['aaa','bbb','ccc'],',');//第二个参数表示分隔符,将第一个参数列表里的数据用这个分隔符拼接起来
print('sb:${sb}');
..的作用就是可以实现链式调用,writeAll方法:
external void writeAll(Iterable objects, [String separator = ""]);
方法点进去可以看到声明的时候我们需要传两个参数,集合、切割符号,这正如输出的结果我们看到确实如此!
Booleans 布尔值 (bool)
bool的运用很简单,跟Java是一样的:
bool isNull;
print('isNull:${isNull}');
运行结果:
大家肯定知道了,因为isNull没有初始化所以默认值肯定是null,那如果我们初始化之后输出就会如下:
isNull:false or isNull:true
List 列表(数组 List)
//声明一个自动长度的数组
List growableList = new List();
growableList..add(1)..add(2)..add('HelloWorld');
print('growbleList: ${growableList}');
这里我们用到了new这个关键字进行List实例的创建,通过..符号进行链式操作添加集合数据,打印如下:
growbleList: [1, 2, HelloWorld]
也可以换一种声明方式:
var list = List(6);
list[0] = "a";
list[1] = "b";
list[2] = "c";
list[3] = "d";
list[4] = "e";
list[5] = "f";
print('list:${list}');
这里我们声明了一个固定长度的集合并且挨个添加数据,打印如下:
list:[a, b, c, d, e, f]
我们还可以固定元素:
var typeList = List<String>();
typeList..add("1")..add("2")..add("3");
print('typeList:${typeList}');
如果放入其他的类型编译器就会报错。
还可以这样声明:
var varList = [1, 2, 3];
List ls = [1, 2, 3];
都是可以的。
还有List的一些常用方法,比如获取第一个元素、最后一个元素等,还可以直接增删、添加集合addAll等方法跟Java很类似,方法名都是顾名思义,很容易理解,这里就不一一列举了!
Maps 键值对集合 (Map)
Map的声明有两种方式:
1、直接声明,用{}表示,里面写key和value,每组键值对中间用逗号隔开。
Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '腾讯', 'baidu': '百度'};
// 输出:{Alibaba: 阿里巴巴, Tencent: 腾讯, baidu: 百度}
print(companys);
2、先声明,再赋值
Map schoolsMap = new Map();//这里用var声明也是可以的
schoolsMap['first'] = '清华';
schoolsMap['second'] = '北大';
schoolsMap['third'] = '复旦';
// 打印结果 {first: 清华, second: 北大, third: 复旦}
print(schoolsMap);
看起来是不是也是很容易呢!
接下来看一下它的Api:
Map中的赋值可以这样做:
// Map的赋值,中括号中是Key,这里可不是数组
aMap[1] = '小米';
相同的Key可以覆盖value数值,key是唯一的,value可以时null也可以是空‘’。
// 检索Map是否含有某Key
assert(aMap.containsKey(1));
//删除某个键值对
aMap.remove(1);
可以看出它的api也是很容易,相比Java有些地方我觉得方便不少呢!
注意事项:
// 注意事项
// 1.map的key类型不一致也不会报错。
// 2.添加元素的时候,会按照你添加元素的顺序逐个加入到map里面,哪怕你的key,
// 比如分别是 1,2,4,看起来有间隔,事实上添加到map的时候是{1:value,2:value,4:value} 这种形式。
// 3.map里面的key不能相同。但是value可以相同,value可以为空字符串或者为null
Set 集合 (Set)
Set 集合 (Set)
set是无重复列表
看下面:
var dynamicSet = Set();
dynamicSet.add('a');
dynamicSet.add('b');
dynamicSet.add('c');
dynamicSet.add('1');
dynamicSet.add('1');
print('dynamicSet :${dynamicSet}');
这里会输出:
dynamicSet :{a, b, c, 1}
看到重复的不存在了!
set里面有一个方法difference(),用来返回两个set之间交集,比如,a.difference(b),则返回a有但是b没有的,反之则反。
intersection这个方法是返回两个集合的交集共有的;
union这个方法返回两个集合的并集。
Runes 符号字符
//Runes用于在字符串中表示Unicode字符 //https://copychar.cc/emoji/
String runesStr = '👄';
print(runesStr);
print(runesStr.length); //表示占 2 个 16 位字符
print(runesStr.runes.length); //表示占 1 个 32 位字符
Runes runes = new Runes('\u{1f605} \u6211');
var str1 = String.fromCharCodes(runes); //使用String.fromCharCodes显示字符图形
print(str1);
String str2 = '\u{1f605} \u6211'; //如果非4个数值,需要把编码值放到大括号中
print(str2);
上篇就到这里,下篇待续……
如果你从事Android开发,具备1年以上工作经验,希望深入浅出了解Android flutter、UI等技术要点,渴望实现技术和职业成长上的双重突破,那么以下福利就很适合你:
福利1 免费直播课程
《腾讯课堂Android高级开发工程师系列直播》
适听人群:Android中、高级开发工程师
3.20-3.23 连续7天每晚8点准时直播,持续进行
▼
3月26日:还不会玩JVM就OUT了,一节课用实战告诉你正在直播
3月27日:架构师or码农—架构师必备Android AOP编程
3月28日:实现安全可靠的Android网络连接
3月29日:Handler源码分析与手写handler通信技术框架
3月30日:Android高级必备秘密武器-Navigation
3月31日:Android进阶必学-手写butterknife框架
4月1日:组件化架构演进之路-路由框架原理与实现
福利2 Android开发资料包
该资料包中主要包括「Java语言进阶与Android相关技术核」、「2)App开发框架知识体系(app亦对象)」、「360° Android app全方位性能调优」、「Android前沿技术」、「NDK 模块开发」等内容,全方位扩充你的知识体系。
![](https://img.haomeiwen.com/i15233518/7f44b8bbf5efde4f.png)
![](https://img.haomeiwen.com/i15233518/2e7288ff923a2384.png)
想要参与Android进阶免费系列直播课
以及获取Android开发工程师资料包的同学,
点击加入:加入
免费课程,名额有限,先到先得~~