语言简介
Dart
是由谷歌开发的计算机编程语言,它可以被用于web、服务器、移动应用 和物联网等领域的开发。
Dart
诞生于2011年,号称要取代JavaScript
。但是过去的几年中一直不温不火。直到Flutter的出现现在被人们重新重视。要学Flutter的话我们必须首先得会Dart。
环境搭建
要在我们本地开发Dart
程序的话首先需要安装Dart Sdk
官方文档 https://dart.dev/get-dart
windows(推荐) http://www.gekorm.com/dart-windows/
mac 如果mac电脑没有安装brew这个工具首先第一步需要安装它: https://brew.sh/
brew tap dart-lang/dart
brew install dart
Dart
开发工具:
Dart
的开发工具有很多: IntelliJ IDEA
、 WebStorm
、 Atom
、Vscode
等
例如在Vscode
中配置Dart
- 找到vscode插件安装dart
- 找到vscode插件安装code runner Code Runner 可以运行我们的文件
第一个程序
main() {
print('hello dart');
}
语法
变量定义
dart
是一个强大的脚本类语言,可以不预先定义变量类型 ,自动会类型推倒。
dart
中定义变量可以通过var
关键字可以通过类型来申明变量。如下:
var str='this is var'; //不指定类型会自动推导为String
String str='this is var';//指定类型,同上
常量
final 和 const修饰符
const值不变 一开始就得赋值,编译期要确定。
final 可以开始不赋值 只能赋一次 ; 它是运行时常量,即在运行时第一次使用前才初始化
永远不改量的量,建议使用final或const修饰它,而不是使用var或其他变量类型。
数据类型
Dart中支持以下数据类型:
常用数据类型:
- Numbers(数值):
- int
- double
- Strings(字符串)
- String
- Booleans(布尔)
- bool
- List(数组)
在Dart中,数组是列表对象,所以大多数人只是称它们为列表 - Maps(字典)
通常来说,Map 是一个键值对相关的对象。 键和值可以是任何类型的对象。每个 键 只出现一次, 而一个值则可以出现多次
//字符串用单引号,或者多引号表示
var str1='this is str1';
var str2="this is str2";
//字符串的拼接
String str1='你好';
String str2='Dart';
print("$str1 $str2");
list的使用
//方式一:定义list,不限类型
var l1=["张三",20,true];
//方式二:定义list,限定类型
var l2=<String>["张三","李四"];
//定义一个空list
var l3 = [];
//定义一个固定长度的list
var l4=List.filled(2, "");
//添加一个成员
l2.add("王五");
//list的长度
l2.length;
//list 空判断
l2.isEmpty;
l2.isNotEmpty;
//倒序
l2.reversed;
l2.reversed.toList();
//添加数组
l2.addAll(['桃子','葡萄']);
//indexOf查找数据 查找不到返回-1 查找到返回索引值
l2.indexOf('苹果');
//删除元素
l2.remove('桃子');
//删除指定位置
l2.removeAt(1);
List myList=['香蕉','苹果','西瓜'];
myList.fillRange(1, 2,'aaa'); //修改
myList.fillRange(1, 3,'aaa');
myList.insert(1,'aaa'); //插入 一个
myList.insertAll(1, ['aaa','bbb']); //插入 多个
print(myList);
List myList=['香蕉','苹果','西瓜'];
var str=myList.join('-'); //list转换成字符串
print(str);
var str='香蕉-苹果-西瓜';
var list=str.split('-');
print(list);
List myList=['香蕉','苹果','西瓜'];
for(var i=0;i<myList.length;i++){
print(myList[i]);
}
//使用forEach遍历
for(var item in myList){
print(item);
}
//或者
myList.forEach((value){
print("$value");
});
//map方法映射为新数组
List myList=[1,3,4];
var newList=myList.map((value){
return value*2;
});
print(newList.toList());
//any的使用
List myList=[1,3,4,5,7,8,9];
var f=myList.any((value){ //只要集合里面有满足条件的就返回true
return value>5;
});
print(f);
//where的使用 筛选
List myList=[1,3,4,5,7,8,9];
var newList=myList.where((value){
return value>5;
});
print(newList.toList());
//every的使用
List myList=[1,3,4,5,7,8,9];
var f=myList.every((value){ //每一个都满足条件返回true 否则返回false
return value>5;
});
print(f);
map的使用
//第一种定义 Maps的方式
var person={
"name":"张三",
"age":20,
"work":["程序员","送外卖"]
};
//第二种定义 Maps的方式
var p=new Map();
p["name"]="李四";
p["age"]=22;
p["work"]=["程序员","送外卖"];
set与list相互转化
var s=new Set();
s.add('香蕉');
s.add('苹果');
print(s.toList()); //set转化为list
List myList=['香蕉','苹果','西瓜','香蕉','苹果','香蕉','苹果'];
var s=new Set();
s.addAll(myList); //list 转化为set, 去重
print(s);
map的使用
Map person={
"name":"张三",
"age":20
};
var m=new Map();
m["name"]="李四";
print(person);
//常用属性:
Map person={
"name":"张三",
"age":20,
"sex":"男"
};
print(person.keys.toList());
print(person.values.toList());
print(person.isEmpty);
print(person.isNotEmpty);
//常用方法:
Map person={
"name":"张三",
"age":20,
"sex":"男"
};
person.addAll({
"work":['敲代码','送外卖'],
"height":160
});
print(person);
person.remove("sex");
print(person);
print(person.containsValue('张三'));
函数
内置方法/函数:
print();
自定义方法:
自定义方法的基本格式:
返回类型 方法名称(参数1,参数2,...){
方法体
return 返回值;
}
自定义方法
//基本的自定义方法
int getNum(){
var myNum=123;
return myNum;
}
//演示方法的作用域
void xxx(){
//在方法中定义方法,作用域仅限于本方法
aaa(){
print(getList());
print('aaa');
}
aaa();
}
自定义方法参数
//普通参数
int sumNum(int n){
var sum=0;
for(var i=1;i<=n;i++)
{
sum+=i;
}
return sum;
}
//定义一个带可选参数的方法 ,最新的dart定义可选参数需要指定类型默认值
String printUserInfo(String username,[int age=0]){ //行参
if(age!=0){
return "姓名:$username---年龄:$age";
}
return "姓名:$username---年龄保密";
}
//定义一个命名参数的方法,最新的dart定义命名参数需要指定类型默认值
String printUserInfo(String username, {int age = 0, String sex = '男'}) {//行参
if (age != 0) {
return "姓名:$username---性别:$sex--年龄:$age";
}
return "姓名:$username---性别:$sex--年龄保密";
}
print(printUserInfo('张三', age: 20, sex: '未知'));
//匿名方法
var fn=(){
print('我是一个匿名方法');
};
fn();
//把方法当做参数的方法
fn1() {
print('fn1');
}
//fn2方法
fn2(fn) {
fn();
}
闭包
闭包: 函数嵌套函数, 内部函数会调用外部函数的变量或参数, 变量或参数不会被系统回收(不会释放内存)
闭包的写法:
函数嵌套函数,并return 里面的函数,这样就形成了闭包。
闭包的特点:
1.常驻内存 (全局变量的特点)
2.不污染全局 (局部变量的特点)
//闭包
fn() {
var a = 123; /*不会污染全局 常驻内存*/
return () {
a++;
print(a);
};
}
//在调用时,打印值会一直增加
var b = fn();
b();
b();
b();
函数的其他使用
箭头函数等
List list=['苹果','香蕉','西瓜'];
list.forEach((value){
print(value);
});
//注意和方法的区别: 箭头函数内只能写一条语句,并且语句后面没有分号(;)
list.forEach((value)=>print(value));
面向对象
Dart
所有的东西都是对象,所有的对象都继承自Object
类。
Dart
是一门使用类和单继承的面向对象语言,所有的对象都是类的实例,并且所有的类都是Object
的子类
一个类通常由属性和方法组成。
Dart和其他面向对象语言不一样,Data中没有 public private protected这些访问修饰符合
但是我们可以使用_把一个属性或者方法定义成私有。
Dart中的静态成员:
1.使用static 关键字来实现类级别的变量和函数
2.静态方法不能访问非静态成员,非静态方法可以访问静态成员
class Person {
//最新版本的dart中需要初始化不可为null的实例字段,如果不初始化的话需要在属性前面加上late
late String name;
late int age;
//默认构造函数的简写
Person(this.name, this.age);
Person.now() {
print('我是命名构造函数');
}
Person.setInfo(String name, int age) {
this.name = name;
this.age = age;
}
void printInfo() {
print("${this.name}----${this.age}");
}
}
void main() {
//命名构造函数的调用
var d=new DateTime.now(); //实例化DateTime调用它的命名构造函数
print(d);
Person p1=new Person('张三', 20); //默认实例化类的时候调用的是 默认构造函数
Person p1=new Person.now(); //命名构造函数
Person p2 = new Person.setInfo('李四', 30);
p2.printInfo();
}
Dart
中的类的继承:
1. 子类使用extends关键词来继承父类
2. 子类会继承父类里面可见的属性和方法 但是不会继承构造函数
3. 子类能复写父类的方法 getter和setter
class Person {
late String name;
late num age;
Person(this.name,this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
}
class Web extends Person{
Web(String name, num age) : super(name, age){
}
}
继承方法的覆写
class Person {
String name;
num age;
Person(this.name,this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
work(){
print("${this.name}在工作...");
}
}
class Web extends Person{
Web(String name, num age) : super(name, age);
run(){
print('run');
}
//覆写父类的方法
//可以写也可以不写 建议在覆写父类方法的时候加上 @override
void printInfo(){
print("姓名:${this.name}---年龄:${this.age}");
}
work(){
print("${this.name}的工作是写代码");
}
}
main(){
Web w=new Web('李四',20);
w.printInfo();
w.work();
}
抽象类
- 抽象类通过abstract 关键字来定义
- Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。
- 如果子类继承抽象类必须得实现里面的抽象方法
- 如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。
- 抽象类不能被实例化,只有继承它的子类可以
extends抽象类 和 implements的区别:
- 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类
- 如果只是把抽象类当做标准的话我们就用implements实现抽象类
接口
和Java一样,dart也有接口,但是和Java还是有区别的。
首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。
同样使用implements
关键字进行实现。一个类可以实现多个接口。
但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。
而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。
建议使用抽象类定义接口。
abstract class Db{ //当做接口 接口:就是约定 、规范
late String uri; //数据库的链接地址
add(String data);
save();
delete();
}
class Mysql implements Db{
String uri;
Mysql(this.uri);
add(data) {
print('这是mysql的add方法'+data);
}
delete() {
return null;
}
save() {
// TODO: implement save
return null;
}
remove(){
}
}
class MsSql implements Db{
late String uri;
add(String data) {
print('这是mssql的add方法'+data);
}
delete() {
return null;
}
save() {
return null;
}
}
main() {
Mysql mysql=new Mysql('xxxxxx');
mysql.add('1243214');
}
Dart特性mixins
mixins的中文意思是混入,就是在类中混入其他功能。
在Dart中可以使用mixins实现类似多继承的功能。
因为mixins
使用的条件,随着Dart版本一直在变,这里讲的是Dart2.x中使用mixins的条件:
- 作为mixins的类只能继承自Object,不能继承其他类
- 作为mixins的类不能有构造函数
- 一个类可以mixins多个mixins类
- mixins绝不是继承,也不是接口,而是一种全新的特性
class A {
String info="this is A";
void printA(){
print("A");
}
}
class B {
void printB(){
print("B");
}
}
class C with A,B{
}
void main(){
var c=new C();
print(c is C); //true
print(c is A); //true
print(c is B); //true
}
泛型
通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)
//定义泛型方法
T getData<T>(T value){
return value;
}
//泛型类
abstract class Cache<T> {
getByKey(String key);
void setByKey(String key, T value);
}
class FileCache<T> implements Cache<T> {
getByKey(String key) {
return null;
}
void setByKey(String key, T value) {
print("我是文件缓存 把key=${key} value=${value}的数据写入到了文件中");
}
}
class MemoryCache<T> implements Cache<T> {
getByKey(String key) {
return null;
}
void setByKey(String key, T value) {
print("我是内存缓存 把key=${key} value=${value} -写入到了内存中");
}
}
void main() {
// MemoryCache m=new MemoryCache<String>();
// m.setByKey('index', '首页数据');
MemoryCache m = new MemoryCache<Map>();
m.setByKey('index', {"name": "张三", "age": 20});
}
库
在Dart中,库的使用时通过import关键字引入的。
library指令可以创建一个库,每个Dart文件都是一个库,即使没有使用library指令来指定。
Dart中的库主要有三种:
- 我们自定义的库
import ‘lib/xxx.dart’; - 系统内置库
import ‘dart:math’;
import ‘dart:io’;
import ‘dart:convert’; - Pub包管理系统中的库
https://pub.dev/packages
https://pub.flutter-io.cn/packages
https://pub.dartlang.org/flutter/
1、需要在自己想项目根目录新建一个pubspec.yaml
2、在pubspec.yaml文件 然后配置名称 、描述、依赖等信息
3、然后运行 pub get 获取包下载到本地
4、项目中引入库 import ‘package:http/http.dart’ as http; 看文档使用
库中类名冲突的解决
当引入两个库中有相同名称标识符的时候,如果是java
通常我们通过写上完整的包名路径来指定使用的具体标识符,甚至不用import都可以,但是Dart里面是必须import的。当冲突的时候,可以使用as关键字来指定库的前缀。
如下所示:
import 'lib/Person1.dart';
import 'lib/Person2.dart' as lib;
main(List<String> args) {
Person p1=new Person('张三', 20);
p1.printInfo();
lib.Person p2=new lib.Person('李四', 20);
p2.printInfo();
}
延迟加载
也称为懒加载,可以在需要的时候再进行加载。
懒加载的最大好处是可以减少APP的启动时间。
懒加载使用deferred as关键字来指定,
如下所示:
import 'package:deferred/hello.dart' deferred as hello;
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
其他
异步的实现
async是让方法变成异步。
await是等待异步方法执行完成。
async和await
这两个关键字的使用只需要记住两点:
1.只有async方法才能使用await关键字调用方法
2.如果调用别的async方法必须使用await关键字
Null safety
以及可空类型 非空断言
Null safety
翻译成中文的意思是空安全。
? 可空类型
! 类型断言
示例如下:
String? username="张三"; // String? 表示username是一个可空类型
username=null;
print(username);
String? str="this is str";
str=null;
print(str!.length);
//类型断言: 如果str不等于null 会打印str的长度,如果等于null会抛出异常
identical
dart:core 库中identical 函数:检查两个引用是否指向同一个对象。
var o = new Object();
var isIdentical = identical(o, new Object()); // false, different objects.
isIdentical = identical(o, o); // true, same object
//const关键词在多个地方创建相同的对象的时候,内存中只保留了一个对象。
isIdentical = identical(const Object(), const Object()); // true, const canonicalizes