抓住线上经济的新机遇
概述
Dart 从 2.0 开始变为强类型语言,静态类型。这点和 Java、C# 等比较相似。也就是说在编译时就已经知道变量的类型,就是静态类型语言。开发人员q ? K在开发的时候需要指定变量的类型。这有什么优点呢?就是所有类型检查都可以通过编译器来完成。可以提前- . } 8 ; R |预报一些琐碎的错误。同时 Darto H _ 1 q 还是面向对象的编程语言。像 python、Java、K# j o ] h ~ K G ^oltin、PHP 等等都是面向对象的语言。
Dart 的特Z N K :性
JIT: 即时编译,开发期间做到更快的编译和更快的代码重载。但也有劣势就是在运行时需要将代码编译为机械码,那么直观感受就是慢,所以我们在开发期间有时候会发现卡顿,但是打 release 包之后效果会变好。
AOT: 事前编译,release 期间已经编译为二进制代码,所以加载会更快更流畅。
常用数据类
任何语言的基础都是数据类型,dart 也一样。dart 中主要有数字、字符串、布尔、集合和 var 类型
num 类型
num 是 da6 & , M r j s Mrt 中的数字类型的父类,它有两个子类: int 和 double。当类型指定为 num 的时候可以赋b [ g ~ K &值为小数也可以赋值为整数,但是一旦指定了某一个具体的类型,就只能赋值w 7 _ h _ 0 D u这一类型的值。
void _boolType() { bool success = true, f / M F ; //定义bool值为true bool failure = false; //定义bool值m : O f &为faF g y K c Vlse
print(success || fail& D B j y Q k } vure); //或运算 输出 true printX 4 k 9 g ) |(success && failure); //且运算 输出 false }其中这些类型之间是可以相互转换的,如:
print(num1.abs()X d Z 9 3 &); // 取绝对值 输出 2.0 print(num2.toDouble()); // 转为小数 输出4.0 print(num3.toString()); // 转为字符串 输出\"5\" print(num4.toInt()); // 转为整数 输出 6String 类型
Stp # e ) l ~ ? q Ering 的定义也比较简单,它可以使用单引号也可以使用 - , [双引号定义,定义一个3 8 / H 9 R d a D String 类| l E j 4 y #型后面可以通过逗号隔开定义多个变量。在 dart 中拼接字符串可以是 + 号链接,还可以使用 $ 符号进行拼接,如果是变量则直接使用 $xx,如果是表达式则使用 ${xxx} 将其包裹起来。
void _stringType() { String str1 = \'str1\', str2 = \"str2\% D j G f"; //定义字符串str1和str2 Stri+ j 8 J g $ ng str3 = \"字符串数据类型\"; //定义字符串str3 String str4 = \'$ @ ^ %str1=$str1;str2=$str2\'; //通过$符拼接字符串 String str5 = \"stk P { E er1=\" + str1 + \" str3=\"( R s Q H } + str3; //通过+号拼接字符串 }字 f x L 4 b 8的 API,比如字符串截取,获取指定字符串位置,匹配字符串开头等等。
print(str3.substring(1, 5)); //符串数据 输出 符串数据 print(str3.indexOf(\"数据\")); //M 5 : X w A 获取位置 输出 3 print(str3.startsWith(\"字\")); //匹配起始字符串 true print(str3.replaceAll(\"字符串\", \"dart的String\")); //替换 输出dart的String数据类型 pM F T / o t ? Irint(str3.split(\"数\")); //切够字符串 输出布尔类型
Dart 中布尔类型是强 bool 类型,只有 bool 类型D Z } R g 8 2 _的值为 true,才被认为是 true。bool 还有一些常用的运算符比如 || (或) 或者 && (且),在运算的时候,教大家一个口诀就是,且同真为真,或同假为假。
void _bool5 C K T | # ! z ,Type(A = G m j # .) { bool success = true; //定z = k G s义bool值为true bool f} 1 i _ ( oailure = false; //定义bool值为false
print(su, ! uccess || failure); //或运算 输出 true print(success && faiP z o l qlure); //且运算 输出 false }集合类型
dart 中定义集合直接使用 List list=,如果没有指定泛型,默认类型为 dynamic 类型, _ x集合中可以添加任何数据类型的数据,一旦指定了泛型,那么就只能添加约束的类型数据。除了初始化的时候添加元! B % R素另外还可以通过 Az p } h Q ) JPI 的方式像集合中添加数据,add 添加单一数据,addAll 添加集合。+ y [ : ` O还有另外一种方式是通过 List.generate 来生成集合,它的第一个参数表示集合的大小,第二个参数表示集合的元素。
void _listType() { List list = ; //泛型为dynamic //@ f } | 3 = 2 C报 type \'List<ds W z n iynamic>\' is not a subtype of type \'List<int>\'= - k H s R _ 异常 //因为指定了intList的泛型为int 但是list的泛型为dynamic,随意赋值E I M *失败 //List<int> intList = list; List<int> intList2 = ;K D & //定义int集合 list.add(\"hello\"); //添加单一元素 list.f + . 8 eaddAll(intList2); //添加集合 print(list); //输出
Listx } * b w<String> strL{ P a H K q o 6 ~ist = List.gen; Y k y l y u X xerate(2, (index)=> \"我是第$index个元素\"); //通过generate定义一个String集合 print(strList); //输出 }有了集合那么我们就需要遍历它,dart 中常用的遍历集合方式有:
1, 2, 3, \"list\",\"hello\",1, 2, 3, 4, 5上面三种遍历方式输出结果都为:
1, 2, 3, \"list\",\P ~ 7"hello\",1, 2, 3, 4, 5$ 5 K w e q V ?Map 类型
Map 类型是将 key 和j ` ? / x J value 相关联的对象,key 和 value 可以是任意类型的数据,并且 key 是唯一的,如果 key 重复那么后添加的会覆盖之前添加的数据。定义 map 类型直接看代码:
void _mapList() { Map map = {\"lisi\": 20, \"zhangsan\": 24}; //直接通过 {key:value} 方式定义 Map map2 = {}; mapZ + 82 = 20; map2 = \"24\"; //上面两个效果是一样的且都没有指定泛型。 Map<int, int> intMap = {1: 2, 3: 4}; //指定map的泛型 }下面我们看下 Map 的遍历:
map.f: x { 7orEach((key, value) { print( \"key:$key,value:} J o 3 m b N z$value\"); //输出 key:lisi,value:20 和 key:zhangsan,value:2M u (4 });
map.map((key, value) { return MapEntry(value, key); //返回一个新的map对象,我们将key va( ) s I 3 v x Olue值进行颠倒后R { ( * h v返回 }).forEach((key, value) { print(\"key:$key,value:$value\{ 7 0 = . m z v i"); //输出 key:20,valC @ 6 oue:lisi 和 key:24,value:zhangsan });
for(var key in map.keys){ //遍历map的key元素 同理还可a ) ! 8 B m以遍历map.values print(key); //输出 lisi 和 zhangsan }dynamic、var、Object 的区别
dynami9 Z G ? S & 3 Pc: 动态数据类型,是所有 dart 对象的基础类型, 在大多数情况下,通常不直接使用它,V b V K m 2 p d通过它定义的变量会关闭类型检查,这意味着 dynamic x4 ` f J r z f = \'hello world\6 Q $ ; t'; 调用 x.foo() 方法时 ; $ P K | +静态类型检查不会报错,但是运行时会 cras( D - * ] * _ oh,因为 x 并没有 foo() 方法,所以建议大家在编程时不要直接使用 dynamic。
varF 6 A V & : P: 是一个关键字,意思是 \"我不关心这里的类型是什么。\",系统会自动推断类型 runtimeType;而且一旦指定了类型,就不可以修改。
Object: 是 dart 对象的基类,当你定义: Object obj=xxx 时这时候系统会认为 obj 是个对象,你可以调* f q e 6 A用 obj 的 toString() 和 hashCode() 方法,因为 Object 提供了这些方法,r 8 W n h但是如果你尝试调用 obj.foo() 时,静态类型检查会进行报错。
综上不难看出 dynamiM r z tc 与 Object 的最大的区别是在静态类型检查上。
面向对象
类的定义和构造
定义一个 dart 类,使用 class 关键字加上类名,构造方法和类名相同,默认所有的类都是继承 Object 的。其中可以定义一些方法和变量,如:
class Person { String name; int age; //标准构造方法 Persoe h m sn(tJ E 0 rhis.name, this.1 | g a ~age);
//重载 b G 6 N d H B父类的toString方法 也是多态的重要体现 @override String toString() { return \"name=$name,age=$age\"; }}一个类继承另一? c S [ r (个类使用关键字 extends,如果父类没有默认无参构X |造函数,那么子类需要使用 super 对父类进行初始化,子类的变量使用 this.xxx 来指定初始化,如:
class Worker extends PersB D ron {
String workTw 2 s r : w o 7ype; String workAddress; //通过this来初始化子类字段,将其他字段交由父类初始化 Worker(this.workTypv & n Q d n Le,this.workAddress,String nl _ H W a L _ame, int age) : super(name, age);}上面代码中的: sups v 1 ^er(name,age) 被称作为初始化列表,除了调用父类构造器,还可以初始化实例变量,不同的初始化变量之间用逗号隔y R R j v 7 C 9 M开。
class Worker extends Person {
String workType; String workAddress; String companyName; //通过this来初始化子类字段,将其他字段交由父类初始化,这里指定了companyName的初始化。 //如果要初始化变量,那么其不可以在构s - 3 5 v n #造方法中定义 Worker(tz x w W ? / ! [ Nhis.workType, this.workAddress, String name, int aX # y Sge) : companyName = \"world\", super(name, age);}我们还可以通过命名构造函数的方式初始化实例类。使用就是类名.xx() 即可,主要注意的是当有变量的类型是 final 的时候p c r Z h u o w,命名构造方法就要求其在构造方法中指定进行初始化。
class Worker extends Person {
...... //命名构造函数 Worker.begin(Worker wH 9 1 { c = A 3 iork)$ b m : super(work.name, work.aC 7 W $ xge) { print(\"命名构造函3 = v C T $ r数\"); }
//假如有变量final String workAddress,那么N V ~ -就需要在构造方法中指定: //Worker.begin(Worker work,this.= * ; w j o 4 q workAddresso : | { i ^) : super(work.name, work.age) { // print(\"命名构造函数\"); //}
}工厂构造函数就是都只返回同一* y W { R 0 , w =个实例类,可以理解为 Java 中的单例模式。
class Logger { static Logger _logger;
factoV q {ry Logger() { if (_logger == null) { _logger = Logger._initInstance(); } return _logger; } //通过命名构造函数初始化 Logge B i t : T R K n Q # * 9 F g时候非常有用,实际上抽象类中也包含一些实现。如果一个类继承了抽象类要么实现它的抽象方法,要么也将自己定义成抽象类。一个抽象类中不一定要有抽象方法,但是有抽象方法的类一定是抽象类。//抽象u j c y f ^类abstract class Animal { //抽象方法 void eat();}
//实现抽象类M R ; / 7 X % T 8class Dog eP K @ yxtends Anima r = @ ! N H _al { //实现eat方法 @override void eat() { print(\"啃骨头\"); }}
mv C B y n H 在多个类层次结构中重用代码的一种方式。要使用 mixins,在 with 关键字后面跟一个或多个 mixin 的名字 (用$ D + n ^ 3 3 K y逗号分开),并且 with 要用在 extends 关键字之后。
mixins 的特0 % g $ u $征: 实现 mi9 A l )xin ,就创建一个U b M S } z 2 =他们都使用 {} 来定义。
class FunClay 8 l Vss { //city为可选参数,town为默认参数 String fromWhere(country, {String city, String town = \"小红帽村\"}) { if (cith g ] G | n * }y != null) { return \"我来自 $country $city $town\"; } elseB X G r J Y J / i { return \"我来自 $country $town\"; } }}
我们来调用打印下看看:
class Worker extends Person {
....3 ~ e P ,..
factory Worker.workHard(Worker work) { return Worker.begin(wo: U P 7 9rk, \"\"); }}
匿名方法有时候也被称为 lambda 或者 closure 闭包,可以把匿名方法赋值给一个变量,直接调用变量名即可。
var printI = (i) =>o W 9 k M P } {; print(i);
使用:
FunClass funClaN ( Z * : R l ! lss = FunC ] . 6 ] j fClass();funClass.printI(999);
泛型
泛型主要是解决类、接口、方法的复用性、以及对不特定数据类型的支持。
class Cache<T> { static final Map<String, Object> _cached = Map(); void setItem(String key, T value) { _cached = value; } ///泛型方法 T getIG E T % 9 1 m Atem(String key) { ret! 5 O ! t o D l gurn _cached; }}
这里我们定义了一个I } ^ ) u = A 2 x缓存类,存储的类型被定义为泛型,提高代码的复用度。
有时候我们在实现类似通用接口的泛型中,期望, 5 9 ( ! n D的类型是某些特定类型时,g N z ( Y这时可以使用类型约束。
class Member<8 # Y;T extends Person> { T _person; ///泛型作O - } e用:约束参数类型 Member(this._person);
Strint ( v + }g fixedName() { return \'fixed:${_person.name}\'; }}
总结
本文主要是讲解了在 Flutter 中常用到的 dart 的基础知识,当然还有其他很多的知识点没有涉及到。这里推荐几个 dart 学习网站给大家使用。