【自学flutter系列】dart语言学习概览
Flutter 是由Google开发的UI工具包,是采用了 Dart 来编写的框架和 widget。
所以我们要学习Flutter开发,就有必要了解dart语言,不说精通,至少得对dart的一些语法有一些了解。
其实如果你以前有过其它程序开发经验,很快便能掌握dart语法。
和javascript相比, dart是一门强类型的语言,Dart 综合了动态语言和静态语言的特性。
变量与内置类型
变量
声明变量
// 声明变量并赋值 var name = 'Bob' // 如果声明时没有赋值, 默认值为null String name; // name的值为null
final 与const
如果你以后不打算修改一个变量,使用 final 或者 const。 一个 final 变量只能赋值一次;一个 const 变量是编译时常量。
const age = 123; // const 在代码编译时就已经确定了变量的值 final age; // 默认为null age = 123; // 第一次赋值为123 age = 234; // Error 报错, final只能赋值一次
const 关键字不仅仅只用来定义常量。 有时也可以用来创建不变的值, 还能定义构造函数为 const 类型的,这种类型 的构造函数创建的对象是不可改变的。
内置类型
Numbers
- int 整数
- double 浮点数
int x = 1; double y = 2.1; // x = '222' // 报错,x是整数
数字和字符串这间的转换
// String -> int int strToInt = int.parse('1'); // String -> double double strToDouble = double.parse('1.1'); // int -> String String intToStr = 1.toString(); // double -> String String doubleToStr = 3.14159.toStringAsFixed(2);
Strings
Dart 字符串是 UTF-16 编码的字符序列。 可以使用单引号或者双引号来创建字符串
var s1 = 'Single quotes work well for string literals.'; var s2 = "Double quotes work just as well."; // 在字符串中使用表达式 ${expression},如果表达式是个变量,可以省去{}。 // 类似JS里的 `abc${var}` var s = 'string interpolation'; var p = '这是一个表达式${s}'; var k = '这是一个表达式$s'; // 和js一样,可以使用+连接多个字段串 var t = s + p + k;
使用三个单引号或者双引号也可以 创建多行字符串对象
var s1 = ''' You can create multi-line strings like this one. '''; var s2 = """This is also a multi-line string.""";
Booleans(布尔值)
Dart 有一个名字为 bool 的类型。 只有两个对象是布尔类型的:true 和 false 所创建的对象, 这两个对象也都是编译时常量。
通俗地讲就是dart判断bool值就是只能用true和false,像JS的0, 1, null等都能判断表达式真假,dart不能。
var name = 'Bob'; if (name) { // 这里dart会抛出一个异常, 表示name变量不是一个布尔值。 // javascript 可以这样判断, dart 不能 print('Bob'); }
Lists(列表)
相当于JS里的数组,表示为有序的集合。
Maps
相当于JS里的对象字面量, python里的字典.
Map 是一个键值对相关的对象。 键和值可以是任何类型的对象。
var gifts = { // Keys Values 'first' : 'partridge', 'second': 'turtledoves', 'fifth' : 'golden rings' }; // 使用 Map 构造函数也可以实现同样的功能 var gifts = new Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings';
runes
runes 代表字符串的 UTF-32 code points。
symbols
略过
Functions 函数 (方法)
在Dart中, function是一种类型为 Function 的对象,这意味着function可以赋值给变量,也可以当做其他function的参数。 这和Javascript中function比较像。
对于只有一个表达式的function, 可以使用 =>
形式 缩写:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
dart语言函数(方法)有两种参数: 必需的和可选的。 必需的参数在参数列表前面, 后面是可选参数。
可选参数又可以分为命名参数或者基于位置的参数,但是这两种参数不能同时当做可选参数。
参数如果没有设置默认值, 默认值为null。
// 可选命名参数 enableFlags({bool bold, bool hidden}) { // ... } // 可选位置参数 把一些方法的参数放到 [] 中就变成可选 位置参数了 String say(String from, String msg, [String device]) { var result = '$from says $msg'; if (device != null) { result = '$result with a $device'; } return result; }
函数参数到底是值传递,还是地址传递(引用)呢?
// 参数传递简单的数字 void main() { int k = 5; print(k); test(k); print(k); } void test(int a) { a = 77; print(a); } // 返回的结果是 5 77 5 // 函数传递map void main() { Map<int, String> k = { 1: '123', 2: '234' }; print(k); test(k); print(k); } void test(Map a) { a[1] = 'kkkk'; print(a); } // 返回的结果是 {1: 123, 2: 234} {1: kkkk, 2: 234} {1: kkkk, 2: 234}
具体原理也可以可以参照 https://blog.csdn.net/bbdxf/a...
- var a = 10;这种赋值语法的含义是a是指向一个内存对象10的引用(ref).
- var a = 10; var b=a; 则a,b都指向同一个内存对象,即引用同一个内存对象。但是a,b之间没有任何联系。
- 在2的情况下,修改a指向对象的值,b也会跟着改。(矛盾点也在这里!)
- 但是,Dart中不是所有的对象都可以修改的(mutable or immutable),其中number,String,bool等都是不可变类型,每次修改都是产生一个新的对象。而其他大部分对象都是mutable, 所以第3条的情况在面对immutable对象会表现不一致。
看起来和JS的函数参数传递是差不多的。按照JS传参理解的话就是:
简单的如数字,字符串,bool 是值传递。在函数内部对参数变量重新赋值,不会改变函数作用域外的值。Lists, Maps, Functions, 对象等是按引用传递。在函数内部对参数变量重新赋值,函数作用域外的值也会相应地跟着改变
操作符
这节我们主要关注下那些与JS语法中不一样的那些操作符。其它的像 +, -, * , / , >, <, = ,%, ++, -- 等 这些操作符和js里完全是一样的。
// 1 整除 ~/ // 相当于除数取整数部分, assert(5 ~/ 2 == 2) // 相当于JS里的 Math.floor(5/2) assert(5 ~/ 3 == 1) // as 类型转换 // is 如果对象是指定的类型返回 True // is! 如果对象是指定的类型返回 False // 只有当 obj 实现了 T 的接口, obj is T 才是 true。 if (emp is Person) { // Type check emp.firstName = 'Bob'; } (emp as Person).firstName = 'Bob'; // 如果 emp 是 null 或者不是 Person 类型, 则第一个示例使用 is 则不会执行条件里面的代码,而第二个情况使用 as 则会抛出一个异常。 // 赋值操作符 // ??= 有点像是JS里 || 表达式赋值 a = value; // 给 a 变量赋值 b ??= value; // 如果 b 是 null,则赋值给 b; // 如果不是 null,则 b 的值保持不变 // 条件表达式 ?? // 相当于js里的&& // 级联操作符 .. // 级联操作符 (..) 可以在同一个对象上 连续调用多个函数以及访问成员变量。 // 条件成员访问 ?. 和 . 类似,但是左边的操作对象不能为 null,例如 foo?.bar // 如果 foo 为 null 则返回 null,否则返回 bar 成员 querySelector('#button') // Get an object. ..text = 'Confirm' // Use its members. ..classes.add('important') ..onClick.listen((e) => window.alert('Confirmed!')); // 和上面的代码和下面的代码功能一样: var button = querySelector('#button'); button.text = 'Confirm'; button.classes.add('important'); button.onClick.listen((e) => window.alert('Confirmed!'));
流程控制
流程控制和其它编程语言的基本上是一样的。
需要注意的是条件表达式(if...else...)的判断条件只能是True和false。
异常处理
Dart 提供了 Exception 和 Error 类型, 以及一些子类型。你还 可以定义自己的异常类型。 Dart 代码可以 抛出任何非 null 对象为异常,不仅仅是实现了 Exception 或者 Error 的对象。
Throw 抛出异常
try...catch 捕获异常
Finally 要确保某些代码执行,不管有没有出现异常都需要执行
Classes 类
class Point { // 类属性 num x; num y; // this 关键字指当前的实例。 // 构造函数 Point(this.x, this.y) // 相当于 //Point(num x, num y) { // this.x = x; // this.y = y; //} // 命名构造函数 Point.fromJson(Map json) { x = json['x']; y = json['y']; print('in Super Classes'); } // 方法 num distanceTo(Point other) { var dx = x - other.x; var dy = y - other.y; return sqrt(dx * dx + dy * dy); } // Getter, setters // 每个实例变量都隐含的具有一个 getter, 如果变量不是 final 的则还有一setter。 // 你可以通过实行 getter 和 setter 来创建新的属性, 使用 get 和 set 关键字定义 getter 和 setter } // 调用超类构造函数 class ChildClass extends Point { // 采用 ChildClass.fromJson(Map json) : super.fromJson(data) { print('in Child Classes') } }
抽象类与抽象函数
// 使用 abstract 修饰符定义一个 抽象类—一个不能被实例化的类。 抽象类通常用来定义接口, 以及部分实现 abstract class Doer { // 定义一个抽象类 void doSomething(); } class EffectiveDoer extends Doer { void doSomething() { // 实现这个抽象类 } }
扩展类 (extends)
使用 extends 定义子类, supper 引用 超类
class Television { void turnOn() { _illuminateDisplay(); _activateIrSensor(); } void test() { print('Television') } } class SmartTelevision extends Television { void turnOn() { super.turnOn(); _bootNetworkInterface(); _initializeMemory(); _upgradeApps(); } // 使用@override 注解来 表明你的函数是想覆写超类的一个函数 @override void test() { print('SmartTelevision') } }
枚举类型
// 使用 enum 关键字来定义枚举类型 enum Color { red, green, blue } assert(Color.red.index == 0); assert(Color.green.index == 1); assert(Color.blue.index == 2);
类变量和类函数
何为类变量和类函数? 即不需实例化该类,使用类名.即可使用的变量或函数
使用 static 关键字来实现类级别的变量和函数。
import 'dart:math'; class Point { num x; num y; Point(this.x, this.y); static num distanceBetween(Point a, Point b) { var dx = a.x - b.x; var dy = a.y - b.y; return sqrt(dx * dx + dy * dy); } } main() { var a = new Point(2, 2); var b = new Point(4, 4); var distance = Point.distanceBetween(a, b); assert(distance < 2.9 && distance > 2.8); }
泛型
这个泛型对于前端开发人员来说是个新概念。如果你查看 List 类型的 API 文档, 则可以看到 实际的类型定义为 List<E>。 这个 <…> 声明 list 是一个 泛型 (或者 参数化) 类型。 通常情况下,使用一个字母来代表类型参数, 例如 E, T, S, K, 和 V 等。
例如,如果你希望一个 list 只包含字符串对象,你可以 定义为 List<String>, 这样你、 你的同事、以及所使用的工具 ( IDE 以及 检查模式的 Dart VM )可以帮助你检查你的代码是否把非字符串类型对象给放到 这个 list 中了。
另外一个使用泛型的原因是减少重复的代码。 泛型可以在多种类型之间定义同一个实现, 同时还可以继续使用检查模式和静态分析工具提供的代码分析功能。
var names = new List<String>(); names.addAll(['Seth', 'Kathy', 'Lars']); // 错误 names.add(42); // 减少代码量 // 对象缓存 abstract class ObjectCache { Object getByKey(String key); setByKey(String key, Object value); } // 缓存字符串 abstract class StringCache { String getByKey(String key); setByKey(String key, String value); } .... // 使用泛型后, 定义一个通用的实现 abstract class Cache<T> { T getByKey(String key); setByKey(String key, T value); } // T 是一个备用类型。这是一个类型占位符, 在开发者调用该接口的时候会指定具体类型 // 泛型函数 T first<T>(List<T> ts) { // ...Do some initial work or error checking, then... T tmp ?= ts[0]; // ...Do some additional checking or processing... return tmp; }
异步支持
Dart 有一些语言特性来支持 异步编程。 最常见的特性是 async 方法和 await 表达式。
Dart 库中有很多返回 Future 或者 Stream 对象的方法。 这些方法是 异步的。
是不是很眼熟。 async, await 是我们在写JS中经常见到的呀。那在我的理解是:
dart中的Future和Stream对象就相当于JS中的Promise对象
async 方法和 await 表达式 使用的JS中的使用是一样的。
以上这些纯属个人学习记录,本人是一名前端开发,对JS比较熟悉,所以有些地方会套用些JS的语法来做说明
如有错误及不妥之处,欢迎评论留言指出。
上一篇: 【自学flutter系列】flutter 开发环境搭建