Dart
是由谷歌开发的计算机编程语言,它可以被用于web、服务器、移动应用 和物联网等领域的开发。
Dart
诞生于2011年,号称要取代JavaScript
。但是过去的几年中一直不温不火。直到Flutter的出现现在被人们重新重视。要学Flutter的话我们必须首先得会Dart。
官网:https://dart.dev/
要在我们本地开发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
第一个程序
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中支持以下数据类型:
常用数据类型:
//字符串用单引号,或者多引号表示
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();
}
抽象类
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的条件:
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();
// m.setByKey('index', '首页数据');
MemoryCache m = new MemoryCache<Map>();
m.setByKey('index', {"name": "张三", "age": 20});
}
在Dart中,库的使用时通过import关键字引入的。
library指令可以创建一个库,每个Dart文件都是一个库,即使没有使用library指令来指定。
Dart中的库主要有三种:
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