Dart 入门
Posted 杨斌并
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dart 入门相关的知识,希望对你有一定的参考价值。
dart入门
- 变量
你可以通过 var 或者特定的类型来修饰变量,如果变量的类型不是固定的,也可以通过 dynamic 或者 Object 来修饰。如:
//类型推断
var name = 'Ybb';
//指定类型
String name = 'Ybb';
//类型不局限于string
dynamic name = 'Ybb';
- 默认值
Dart 中声明时如果未初始化,会被自动初始化为null:
int num;
assert(num == null);
- final 与 const
final 和 const 标识该变量只能被赋值一次,区别在于 final 是运行时赋值,const 是编译时赋值。
final String nickname = 'Jack';
//final修饰时,可省略类型声明
final name = 'Jack';
const不仅可以用来声明变量,还能用来创建常量值,如:
//此时不能在对列表a进行更新操作
var a = const [1, 2];
//注意以下const 修饰的区别
var foo = const [];
const baz = [];//Equivalent to `const[]`
...
foo = [1, 2, 3]; //Was const[]
baz = [42]; //Error:Constant variables can't be assigned a value.
数据类型
Dart 语言支持的数据类型与 Java 类似,但也有所不同,下面我们来按照“求同存异”的法则来分别认识它们。
- 数字类型
Dart 中的数字类型只有两种:Int 和 double。与 Java 不同的是,它并没有提供 float 类型。例如,我们可以通过以下方式来定义数字:
// 定义整型
var x = 56;
var hex = 0xDEADBEEF;
//定义双精度类型
var y = 1.199;
var exponents = 1.42e5;
//再来看下常用的数据转换该如何执行:
//String -> int
var a = int.parse('1');
assert(a == 1);
// String -> double
var b = double.parse('1.1');
assert(b == 1.1);
// int -> String
String c = 1.toString();
assert(c == '1');
// double -> String
String d = 3.14159.toStringAsFixed(2);
assert(d == '3.14');
- int 类型可以执行传统的按位移位( <<,>> ),AND( & )和OR( | )运算符,如:
assert((3 << 1) == 6);//0011 <<1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7);//0011 | 0100 = 0111
- 字符串类型
字符串的声明可以通过单引号或者双引号来引入:
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.";
//字符串拼接可以通过 + 或者 换行 来实现,如:
var a = '123' + '456'
var b = '123'
'456';
assert(a == b)
print(a);
// Out: 123456
另外,可以通过三重引号来修饰多行字符串(维持特定格式):
var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";
- 布尔类型
Dart 中的 bool 类型可以通过 if-else 或者是 assert 来检查,如:
// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);
// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);
// Check for null.
var unicorn;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
- 数组类型
在 Dart 语言中,数组即列表,列表即数组。
void main()
var list = [1, 2, 3];
list.add(4);
list.remove(3);
list[1] = 5;
var last = list[list.length - 1];
print('list is $list');
print('last is $last');
另外,你可以通过 … 或者 …?(避免空异常) 来批量插入多个元素:
var list1 = [1, 2, 3];
var list2 = [0, ...list1];
var list3;
var list24 = [0, ...?list3];
除此以外,还可以通过 if 或者 for 条件运算符来插入元素:
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
- Set 和 Map
Dart中的Set是无序的唯一项的集合。要创建一个空集合,有以下两种方式:
var names = <String>;
Set<String> names = ; // This works, too.
// var names = ; // Creates a map, not a set.
通过以下方式创建常量 Set:
final constantSet = const
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
;
// constantSet.add('helium'); // Uncommenting this causes an error.
至于 Map 存储的是键值对数据,key 和 value 可以是任何类型。可以通过以下方式创建一个 Map:
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
// 或者通过以下方式
var gifts =
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
;
函数
Dart 是一门完全面向对象的语言,即使它的函数也是一个对象,并且有自己的类型—— Function。这就意味着函数可以被赋值为一个变量,或者作为一个参数在其他函数之间传递。
对于只包含一个表达式的方法体,你也可以使用 => 的简写形式,如:
void say()
print('123');
// 该写法与以上有同样效果
void say2() => print('123');
此外,函数同样支持类型推断,如:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
// 与下面的效果一样
isNoble(atomicNumber) => _nobleGases[atomicNumber] != null;
- 可选参数
与 kotlin 语言类似,Dart 的 函数同样支持可选参数这一功能,主要分为命名可选参数和位置可选参数,它们不能在一个函数中同时使用。但它们都支持默认参数设置。
命名可选参数
命名可选参数通过花括号 来指定可选的命名参数,如:
void main()
hello(name: 'Tom');
void hello(@required String name='Jack', int age=18)
print('Hello, my name is $name, i'm $age years old.');
我们可以为命名可选参数设置默认值,在使用的时候如果不指定该可选参数的值,那么它就会自动使用默认值。另外,我们可以通过 @required 来标注那些不想被忽略的参数。
位置可选参数
顾名思义,可选位置参数就允许我们在使用某个函数时可以忽略某个参数,如:
void main()
sayHello('Tom', 19);
void sayHello(String name, int age, [String hobby = null])
var result = 'Hello, my name is $name, i'm $age years old';
if (hobby != null)
result += ', my bobby is $hobby.';
print(result);
void main()
sayHello('Tom', 19);
void sayHello(String name, int age, [String hobby = null])
var result = 'Hello, my name is $name, i\\'m $age years old';
if (hobby != null)
result += ', my bobby is $hobby.';
print(result);
匿名函数
不管什么语言,好像都能看到匿名函数的身影,我们可以通过以下方式来简单声明一个匿名函数:
void main()
sayHello('Tom', 19);
void sayHello(String name, int age, [String hobby = null])
var result = 'Hello, my name is $name, i\\'m $age years old';
if (hobby != null)
result += ', my bobby is $hobby.';
print(result);
var loge = (msg) => Logger.print(Logger.Error, msg);
void main()
loge("there has some errors");
- Dart 中 list 就提供了匿名函数 —— forEach,如:
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item)
print('$list.indexOf(item): $item');
);
- 常用操作符
Dart 提供了很多功能强大的操作符,这里列举几个常用的:
-
类型判断
如:is 相当于 Java 中的 instanceof -
整除
如:a ~/ b 等价于 (a /b) as int -
非空调用
如:a?.b 相当于 a == null ? null : a.b -
三目运算
如:a??b 相当于 a == null ? b : a -
三目赋值运算
如:a ??= b 相当于 a = a == null ? b : a -
类型转换
如:a as int 相当于 Java 中的 (int) a
级联操作符
级联操作符用… 来表示,主要用来对一个对象进行连续操作,有点类似 kotlin 中的 apply 和 let,如:
var button = Button(this);
button.text = 'Confirm';
button.color = Color.parse("#f3f355");
button.onClick.listen((v) => toast('Confirmed'));
// 等价于下面写法
Button(this)
..text = 'Confirm' // Use its members.
..color = Color.parse("#f3f355")
..onClick.listen((v) => toast('Confirmed'));
异常处理
- 抛异常
在 Dart 中可以抛出非空对象(不仅仅是 Exception 或 Error)作为异常。抛出异常的方式很简单,只需要这样:
throw 'Out of llamas!';
void distanceTo(Point other) => throw UnimplementedError();
void distanceTo(Point other) => throw UnimplementedError();
- 捕获异常
我们可以通过 try-on 来捕获某个特定异常,如:
try
breedMoreLlamas();
on OutOfLlamasException
buyMoreLlamas();
当然,你可以抛出多个类型的 Exception,但是由第一个 catch 到的分句来处理
如果 catch 分句没有指定类型,那么它可以处理任何类型的异常:
try
throw 'This a Exception!';
on Exception catch(e)
print('Unknown exception: $e');
catch(e)
print('Unknown type: $e');
无论是否发生异常,如果想要执行某段代码,可以通过 finally 实现:
try
throw 'This a Exception!';
catch(e) // 如果去掉 catch 语句,那么异常将会在finally代码块之后传递。
print('Catch Exception: $e');
finally
print('Close');
类和对象
Dart 中,所有的对象都是类的实例,并且所有的类都是 Object 的子类。
类的定义和构造函数
类的定义用 class 关键字,如果未显式定义构造函数,会默认一个空的构造函数,这一点与 Java 不谋而合。另外,Dart 还提供 命名构造函数这一功能,格式为:Class.costructorName(var params)。这种用法在某些场景下很实用,比如:
class Person
String name;
int age;
bool sex;
String hobby;
Person(this.name, this.age, this.sex, this.hobby);
/// 命名构造函数
Person.fromJson(Map json)
print("Person constructor...");
this.name = json['name'];
this.age = json['age'];
this.sex = json['sex'];
this.hobby = json['hobby'];
通过命名构造函数,我就可以直接通过多种方式来生成当前类的实例,这里通过 Json 格式数据生成 Person 对象。另外,如果构造函数只是简单的参数传递,也可以直接在构造函数后加 : 来对参数进行赋值,多个参数可通过 , 相连:
class Point
num x;
num y;
num z;
Point(this.x, this.y, z) //第一个值传递给this.x,第二个值传递给this.y
this.z = z;
Point.fromeList(var list): //命名构造函数,格式为Class.name(var param)
x = list[0], y = list[1], z = list[2]//使用冒号初始化变量
//当然,上面句你也可以简写为:
//Point.fromeList(var list): this(list[0], list[1], list[2]);
String toString() => 'x:x y:x y:x y:y z:$z';
如果你要创建一个不可变的对象,你可以定义编译时常量对象
需要在构造函数前加 const:
class ImmutablePoint
final num x;
final num y;
const ImmutablePoint(this.x, this.y); // 常量构造函数
static final ImmutablePoint origin = const ImmutablePoint(0, 0); // 创建一个常量对象不能用new,要用const
- 属性访问器
即我们常说的 Setter/Getter,主要是用来读写一个属性的方法。每个字段都对应一个隐式的 Getter 和 Setter,但是调用的时候是 obj.name,而不是 obj.name()。当然,你可以通过 get 和 set 关键字扩展功能
来实现自己的 Setter/Getter , 如果字段为 final 或者 const 的话,那么它只能有一个 getter 方法。如:
class Rectangle
num left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
void main()
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
- 工厂构造函数
并不是任何时候我们都需要创建一个新的对象,如:可以返回一个已经缓存好的对象或者该类的子类对象。我们以返回该类的一个缓存对象为例:
class Logger
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>;
factory Logger(String name)
return _cache.putIfAbsent(
name, () => Logger._internal(name));
Logger._internal(this.name);
void log(String msg)
if (!mute) print(msg);
注意:factory 构造函数不能通过 this 关键字来获取类的成员。
- 抽象类
Dart 中并没有 interface 关键字,只有 abstract 来修饰"抽象类",但是,这里的抽象类既可以被继承(extends),也可以被实现(implements)。如:
abstract class Person // 可以不用 abstract 修饰,如果加上 abstract 的话 Person 不能被实例化
String greet(who);
class Student implements Person
String name;
Student(this.name);
String greet(who) => 'Student: I am $name!';
class Teacher implements Person
String name;
Teacher(this.name);
String greet(who) => 'Teacher: I am $name!';
void main()
Person student = new Student('Wang');
Person teacher = new Teacher('Lee');
print( student.greet('Chen'));
print(teacher.greet('Chen'));
同样地,Dart 中的类是单继承,多实现。这里使用的 implements 后,子类 Student 无法去访问父类 Persion 中的变量,但是抽象方法必须显式实现。相反,如果使用 extends 继承,子类就可以直接使用父类的非私有变量,倘若父类不是抽象类,那么子类同样不需要显式实现里面方法。如:
// A person. The implicit interface contains greet().
class Person
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, who. I amwho. I amwho. I am_name.';
// An implementation of the Person interface.
class Impostor implements Person
get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
String greetBob(Person person) => person.greet('Bob');
void main()
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
运算符重载
以下的运算符支持重载功能:
<+|[]>/^[]=<=/&>=*<<==–%>>
这一点与 kotlin 语言中的运算符重载功能类似。我们以下面这个表示平面向量的类为例,为它增加两个向量相加和相减功能:
class Vector
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown. For details, see note below.
// ···
void main()
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
枚举
枚举的使用比较简单,和 Java 中的用法类似,声明的元素 index 值从 0 开始计算。
enum Color red, green, blue
......
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
Mixin 混合模式
Mixins 是一种在多个类的层级中复用类中代码的一种方式。在类名后添加 with 关键字,并在 with 后紧跟类的标识符列表,通过逗号分隔,如:
class Maestro extends Person
with Musical, Aggressive, Demented
Maestro(String maestroName)
name = maestroName;
canConduct = true;
如果想要声明一个混合模式,可以通过 mixin 来代替 class 定义一个不含构造方法的类:
mixin Musical
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe()
if (canPlayPiano)
print('Playing piano');
else if (canConduct)
print('Waving hands');
else
print('Humming to self');
当然,我们也可以指定某个类来使用定义的混合模式,通过 on 关键字:
mixin MusicalPerformer on Musician
// ···
静态变量和函数
定义静态变量和函数的方法与 Java 类似:
class Point
num x, y;
Point(this.x, this.y);
static const originalPoint = Point(0, 0);
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);
// usage
void main()
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
异步操作
Dart 是单线程执行的,如果进行 I/O 操作或进行耗时的操作时,程序可能会发生阻塞。Dart 库中的很多函数都返回 Future 或者 Stream 对象,这些方法都是异步执行的,它们可以在建立一个耗时操作之后返回,而无需等待耗时操作执行完成。
我们可以通过两种方式来实现异步操作:
通过 async 和 await 实现
借助于 Future API 来实现
- async 和 await
通过 async 和 await 关键字,我们可以轻松实现异步操作。要使用 await,必须要将函数用 async 修饰,同时函数会返回一个 Future 对象。简单用法如下:
Future checkVersion() async
try
version = await lookUpVersion();
catch (e)
// React to inability to look up the version
- 生成器
同步生成器 — sync*
值得注意的是,同步生成器会返回 Iterable 对象:
Iterable<int> naturalsTo(int n) sync*
int k = 0;
while (k < n) yield k++;
- 异步生成器 — async*
异步生成器返回 Stream 对象:
Stream<int> asynchronousNaturalsTo(int n) async*
int k = 0;
while (k < n) yield k++;
- yield
通过 yield 在递归中提升性能:
Iterable<int> naturalsDownFrom(int n) sync*
if (n > 0)
yield n;
yield* naturalsDownFrom(n - 1);
将类对象作为函数调用
Dart 允许我们将一个类的对象作为函数来调用,只需要实现 call() 函数即可:
class WannabeFunction
call(String a, String b, String c) => 'aaab $c!';
main()
var wf = new WannabeFunction();
var out = wf("Hi","there,","gang");
print('$out');
以上是关于Dart 入门的主要内容,如果未能解决你的问题,请参考以下文章