前些日子在公司尝试着使用 Flutter 开发一些功能。要想写好 Flutter 程序,首先 Dart 语言是基础。前端
固然,在实际开发中,可能因为时间的关系,不用了解到 Dart 的方方面面才开始 Flutter 的开发,能够边学边用。python
为了造成一个完整的体系,我想先系统的讲解下 Dart 语言,而后在开始 Flutter 相关的介绍。git
Dart 相对于 Java 来讲有更强的变现力,甚至我以为比 Kotlin 还要有表现力。Dart 不只能够用来开发客户端,还能够用来开发Web前端和后端开发。github
因此呢,我以为 Dart 仍是一门值得学习的语言,下面就开始咱们的 Dart 学习之旅吧web
本文是 Dart 相关的第一篇,主要介绍 Dart 语言的变量的定义和类型体系正则表达式
按照惯例,学习一门语言都是从 Hello World 开始的。下面咱们看下 Dart 的 Hello World 程序:express
main(){
var str = "Hello world!";
print(str);
}
复制代码
上面咱们提到了 Dart 是支持类型推导的,因此在定义变量的时候能够经过 var 关键字来定义编程
固然也能够显示的指定 变量的类型,如:后端
// 经过 var 关键字定义变量,省略具体的类型
var str = "Hello world!";
// 显式指定变量类型
String str = "Hello World!"
复制代码
在 Dart 中万物皆对象,如 null、函数、数字 都是对象数组
因此咱们的定义的变量若是没有给初始值,那么这个变量的默认是就是 null
int lineCount;
assert(lineCount == null);
复制代码
定义变量的时候,可使用 final 关键字来修饰,如
final String name = "chiclaim";
name = "johnny"; // Error
复制代码
final定义的变量,在定义的时候就要初始化,而且只能赋值一次
定义变量的时候还可使用 const 关键字来修饰:
const name = "chiclaim"
name = "johnny"; // Error
复制代码
const 关键字修饰变量,说明这个变量是 编译时常量,如数字、字符串字面量都是 编译时常量
const 和 final 区别是 final 表示这个变量只能被赋值一次,const 表示该变量不只只能被赋值一次,而且该变量是一个常量
const 不只能够修饰变量,还能够修饰变量的值,表示该值不能修改:
main(){
// 经过 const 关键字修饰foo变量的值
var foo = const [];
// 因为 foo 的值被 const 修饰,因此不能修改里面的值
// 运行时错误,Unsupported operation: Cannot modify an unmodifiable list
foo[0] = 0;
// 能够赋值,由于 foo 变量没有被 final 或 const 修饰
foo = [1,2,3];
// 因为foo变量被从新赋值,因此能够修改里面的值
foo[0] = 0;
print(foo);
}
复制代码
Dart 类型系统以下所示:
不像 C/C++/Java 等语言,在 Dart 表示数字的类型只有两个:int 和 double
int :表示没有小数点的整型,最大值不大于64-bit(-2^63 ~ 2^63-1)底层依赖的系统最大值也不一样,若是编译后用于JavaScript,则最大值为 -2^53 ~ 2^53-1
double 表示双精度的浮点型
int age = 17;
double weight = 65.5;
double waistline = 30; // 至关于 30.0
复制代码
字符串和数字类型之间互转:
// 字符串转化成整型
int num = int.parse("2");
// 字符串转化成浮点型
double pi = double.parse("3.14");
// 浮点型转成字符串
String piStr = 3.14.toString();
// 浮点型转成用小数表示的字符串(能够选择保留几位小数)
String piAsStringFix = 3.14159.toStringAsFixed(2);
复制代码
一个 Dart 字符串是个 UTF-16 码元(code units)序列,可使用单引号或双引号来建立一个字符串
// 双引号建立一个字符串字面量
var s1 = 'Single quotes work well for string literals.';
// 单引号建立一个字符串字面量
var s2 = "Double quotes work just as well.";
// 单引号建立字符串字面量(须要转义符)
var s3 = 'It\'s easy to escape the string delimiter.'; var s4 = "It's even easier to use the other delimiter."; 复制代码
建立原生(raw)字符串,在字符串前面加上前缀 r:
// 通常 \n 是换行符,若是咱们想把 \n 当作字符串输出时候,也可使用建立原生字符串的方式
var raw = r'In a raw string, not even \n gets special treatment.';
复制代码
咱们还能够将表达式(${expression})嵌入字符串中:
const name = "chiclaim";
// 将表达式${expression}嵌入字符串中
var info = "My name is ${name}";
// 若是表达式是一个标识符,能够省略花括号
var info2 = "My name is $name";
复制代码
字符串的拼接:
// 1. 经过 + 号来拼接字符串
var s2 = 'The + operator ' + 'works, as well.';
// 2. 毗邻的字符串字面量
var s1 = 'String '
'concatenation'
" works even over line breaks.";
// 3. 经过多行字符串(使用三引号)
var s1 = ''' You can create multi-line strings like this one. ''';
var s2 = """This is also a multi-line string.""";
复制代码
// Check whether a string contains another string.
assert('Never odd or even'.contains('odd'));
// Does a string start with another string?
assert('Never odd or even'.startsWith('Never'));
// Does a string end with another string?
assert('Never odd or even'.endsWith('even'));
// Find the location of a string inside a string.
assert('Never odd or even'.indexOf('odd') == 6);
复制代码
// 字符串截取
assert('Never odd or even'.substring(6, 9) == 'odd');
// 使用正则表达式分割字符串,返回字符串集合
var parts = 'structured web apps'.split(' ');
// 经过索引获取字符串的UTF-16编码单元
assert('Never odd or even'[0] == 'N');
// 循环打印字符串中的字符串
for (var char in 'hello'.split('')) {
print(char);
}
// 获取字符串中的全部UTF-16码元
var codeUnitList ='Never odd or even'.codeUnits.toList();
// N 的 ASCII 编码的十进制就是 78
assert(codeUnitList[0] == 78);
复制代码
// 转成大写
assert('structured web apps'.toUpperCase() == 'STRUCTURED WEB APPS');
// 转成小写
assert('STRUCTURED WEB APPS'.toLowerCase() == 'structured web apps');
复制代码
// 去除头尾的空格
print(' hello '.trim() == 'hello');
// 字符串是否为空
print(''.isEmpty);
// 空格不是空字符串
print(' '.isNotEmpty);
// 空格trim后,就变成空字符串
print(' '.trim().isNotEmpty);
复制代码
字符串是不可变的,替换函数不是修改原字符串,而是会产生一个新的字符串
var greetingTemplate = 'Hello, NAME!';
var greeting = greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');
// greetingTemplate didn't change. assert(greeting != greetingTemplate); 复制代码
经过编程的方式生成一个字符串,可使用 StringBuffer 来实现,直到调用 StringBuffer.toString() 函数才会建立字符串
var sb = StringBuffer();
// 经过 .. 实现链式调用
sb
..write('Use a StringBuffer for ')
// 写入一个字符串列表,以空格分割
..writeAll(['efficient', 'string', 'creation'], ' ')
..write('.');
// 建立字符串
var fullString = sb.toString();
assert(fullString ==
'Use a StringBuffer for efficient string creation.');
复制代码
在 Dart 中经过 bool 关键字来描述布尔,布尔有两个值:true和false。 true 和 false 都是编译器常量
bool isSuccess = true;
bool isFailed = false;
复制代码
List不只用来表示List集合(有序的数据集合),也用来表示数组
下面来看下如何建立一个List 字面量
var list = [1, 2, 3]; // 类型推导出list是 List<int>
复制代码
介绍 const 关键字的时候,也用 const 修饰 List 的值 如:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // Error.
复制代码
Dart2.3 提供了展开操做符(... 和 ...?) 让开发者更加方便的将多个值插入到集合中
var list = [1, 2, 3];
// 展开操做符(...) spread operator
var list2 = [0, ...list];
var list;
// 展开操做符(...?) null-aware spread operator
var list2 = [0, ...?list];
复制代码
Dart2.3 除了提供了展开操做符,还有 collection if 和 collection for
// collection if
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
// collection for
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
复制代码
collection if/for 在开发Flutter的时候颇有用,能够简化不少代码
Set 表示一个无序的集合,下面看下如何建立一个 Set 字面量
// halogens is Set<String>
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
复制代码
建立一个空 Set :
// 经过var和泛型推导出Set类型
var names = <String>{};
// 显式指定是Set类型
Set<String> names = {};
须要注意的是下面是建立了一个Map
var names = {};
复制代码
相似地,展开操做符 和 collection if/for 也能够用到 Set 中
Map 是一个 键值对 集合,下面来看下如何建立 Map 字面量:
// gifts is Map<String, String>
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
// nobleGases is Map<int, String>
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
复制代码
须要注意的时候,Key只能出现一次,不然会被后面的替换掉
经过中括号 [] 来添加、修改、获取Map中的元素:
var gifts = Map();
// 添加元素
gifts['first'] = 'partridge';
var gifts = {'first': 'partridge'};
// 获取经过Key获取Map中的元素
assert(gifts['first'] == 'partridge');
var gifts = {'first': 'partridge'};
// 修改Map中的元素
gifts['fourth'] = 'calling birds';
复制代码
相似地,展开操做符 和 collection if/for 也能够用到 Set 中
关于 Dart 的 展开操做符 以及 collection if/for 更多内容能够查看:
(二)Flutter学习之Dart展开操做符 和 Control Flow Collections
在 Dart 中,Rune类型是一个字符串的UTF-32的码点(code points),咱们在介绍 String 类型的时候,提到了 code units
那么在介绍 Rune 以前,咱们先来看下 code points 和 code units 是什么?
Unicode 编码为世界上全部的字母、数字、符号定义了对应的数字来表示
由于 Dart 字符串是 UTF-16 码元的序列,描述 32-bit Unitcode 的字符串须要特殊的语法
一般地, Unicode使用 \uXXXX 描述码点 ,这里的 XXXX 是一个4位十六进制的值,例如描述心形的符号使用 \u2665 表示
若是多于或者少于 4 个十六进制,则须要加上花括号,例如笑的表情使用 \u{1f600}
String 类有几个属性能够提取字符串的 rune 信息 (例如属性 runes),codeUnitAt 和 codeUnit 属性返回 16 bit的 码元(code units)
main() {
var clapping = '\u{1f44f}';
print(clapping);
print(clapping.codeUnits);
print(clapping.runes.toList());
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(new String.fromCharCodes(input));
}
复制代码
在 Dart 全部的类都是继承自 Object,和Java相似。dynamic 和 Object 容许全部的值赋值给它:
dynamic name;
Object email;
main() {
name = "chiclaim";
email = "chiclaim@gmail.com";
}
复制代码
可是他们是两个彻底不一样的概念。你甚至能够把 dynamic 不要当作一个类型看待,dynamic 顾名思义就是动态的意思,它只是告诉编译器不要作类型检查
dynamic name;
Object email;
main() {
// 将 String 赋值给 name
name = "chiclaim";
// 打印 name 的长度
print(name.length);
// 将 int 赋值给name
name = 1;
// 编译器并不会报错(编译时不作类型检查),运行时才会报错
// NoSuchMethodError: Class 'int' has no instance getter 'length'.
print(name.length);
email = "chiclaim@gmail.com";
// 编译器报错,由于 Object 没有 length 属性
print(email.length);
}
复制代码
经过上面的代码示例,相信你对 dynamic 和 Object 的区别有了比较清楚的理解
Dart 在官网的最佳实践中建议开发者,若是你想表达意思是任何对象均可以,使用 Object 代替 dynamic
若是你容许类型推导失败,通常推到失败,编译器会默认给dynamic,可是建议显式地写上 dynamic ,由于代码的阅读者不知道你是忘记了写类型仍是:
// 建议
dynamic mergeJson(dynamic original, dynamic changes){
}
// 不建议
mergeJson(original, changes){
}
复制代码
关于 Dart 变量和类型系统 就讲到这里, 更多的关于 Android
学习资料能够查看个人GitHub: github.com/chiclaim/An…
dart.dev/guides/lang… github.com/acmerfight/…
下面是个人公众号,干货文章不错过,有须要的能够关注下,有任何问题能够联系我: