在Vscode环境下需要安装的依赖
提示所需要的插件
编译代码时可以用到的插件
使用coderrunner我们就无需在控制台输入 dart xx.dart运行代码。可以右键
来执行代码
基本知识快速入门
Hello World
void main(){ //main函数作为函数的入口
print("Hello World"); //每行末尾必须加上分号;dart打印信息使用print函数;
}
在VScode中我们输入main会自动帮助我们生成main函数
void main(List<String> args) { //这里List<String>用到了泛型的知识,后面我们会讲到,args是传递的参数
print("Hello Wrold");
}
注释语法
- 采用//进行语句注释
- 采用 /* */进行块级注释
- 采用///进行文档注释
void main(List<String> args) {
print("Hello Wrold"); //这是一个注释
}
/**
* 这是块级注释
*/
///这是一个文档注释
///
///
///
变量的基本概念
-
变量是一个引用,Dart万物皆为对象,变量存储的是对象的引用。
-
声明变量
- 明确指定类型: int age = 18;
- 不明确类型 var age = 18; dynamic age = 18;
-
Dart中的变量大小写敏感
-
Dart中变量默认值是null
-
Dart变量的值不会进行隐式转换, null不会转换成false
案例一,声明变量
void main(List<String> args) {
// 声明变量
var age1 = 18; //不明确类型
num age2 = 18; //明确为num类型
int age3 = 18; //明确为int类型
print('$age1,$age2,$age3'); //这里使用到了模板字符串,后文会将,这里就是将age1,age2,age3的值打印出来。
}
案例二:变量的默认值为null,大小写敏感,变量不会做隐式转换
void main(List<String> args) {
//dart中变量的默认值是null
int num;
print(num); //null
//dart中变量区分大小写
// print(Num); //报错
//dart中变量的值不会做隐式转换
bool flag;
print(flag); //null
// if(flag){ //不能这么写 一定要flag == false
// print('hello');
// }
}
模板字符串
在js中模板字符串需要在反引号中才能使用,da
class Person{
int age = 18;
Person(this.age);
}
void main(List<String> args) {
int age = 18;
Person p = Person(20);
print('在main函数里age是$age,在类中这里的age是${p.age}'); //在main函数里age是18,在类中这里的age是20
}
常量的概念
- 常量是一旦定义了就无法修改的值
- final与const都可以定义常量
我们需要区分的就是const与final的区别。const要声明编译时能取到的值,final是运行时能取到的值。比如获取当前时间常量,你11点和1点获取的事件是不同的,你就不能用const来定义。
void main(List<String> args) {
var age = 20;
print(age);
var Age = 10;
print(Age);
const String name = 'harry';
// name = 'zhangsan';
final food = 'rice';
print(name);
print(food);
var defaultVale;
print(defaultVale);
}
变量的几个基本类型
数字类型number
数字类型有 int 和 double 还有 num。我们可以把num看成是int和double的父类。
void main(List<String> args) {
int num1 = 10;
double num2 = 2.56;
num num3 = 3.56;
num num4 = 15;
print('$num1,$num2,$num3,$num4'); //10,2.56,3.56,15
}
关于数字类型的一些功能性函数
void main(List<String> args) {
//1.类型转换
double price = 3.15;
print(price.toInt()); //向下取整
//2.四舍五入
print(3.1415926.round()); //3
print(3.6415926.round()); //4
print(3.1415926.toStringAsFixed(4)); //保留四位小数 3.1416
//3.返回余数
print(10.remainder(4)); //2 (remain在英文中是余数的意思,remainder是余数的意思)
//4.数字比较 0:相同 1:大于 -1:小于
print(10.compareTo(12.5)); //-1
//返回最大公约数
print(12.gcd(15)); //3
//科学计数法表示
print(1000.toStringAsExponential(1)); //1.0e+3
}
字符串类型String
字符串类型在Dart中用 String 表示,数据用单引号或双引号扩起来。
void main(List<String> args) {
var str1 = "Hello World";
String str2 = '你好世界\n';
String str3 = '''
Hello
World
'''; //三引号可以表示换行的字符串
print('$str1,$str2 $str3');
}
dart中常用的字符串功能性函数
void main(List<String> args) {
var str1 = "Hello World";
String str2 = '你好世界\n';
//字符串的拼接
print(str1 + str2); //Hello World你好世界
print('$str1$str2'); //Hello World你好世界
//字符串的分隔
print(str1.split(' ')); //以空格进行分隔 [Hello, World]
//字符串的裁切
print(' abc '.trim()); //abc默认帮我们把两边的空格全都删除了,trimeLeft可只删除左边的,trimRight可以只删除右边的
//判断字符串是否为空
print(''.isEmpty); //true
print(''.isNotEmpty); //false
//字符串的替换
print(str1.replaceAll('World', 'Dart')); //Hello Dart
//使用正则表达式进行替换
print('h1k2c45u89'.replaceAll(RegExp(r'\d+'),'_')); //h_k_c_u_
//查找字符串
print(str1.contains('e')); //true
//定位字符串 indexOf从左往右边找(没有找到返回-1,找到返回第一个找到的下标)
print(str1.indexOf('d')); //10
print(str1.indexOf('0')); //-1
//定位字符串lastIndexOf从右往左边找
print(str1.lastIndexOf('e')); //1
}
Boolean
布尔类型比较简单,它的值只有 true 或 false,在 Dart 中用 bool 表示。
void main(List<String> args) {
//声明布尔值
bool flag1 = true;
print(flag1);
bool flag2 = false;
print(flag2);
//显示地进行判断
var flag3;
if(flag3 == null){ //没有三个等号
print('真');
}else{
print('假');
}
}
bool的一些有用的功能性函数
void main(List<String> args) {
var n1 = 0 / 0;
print(n1); //NaN(非数字,这个跟js是一模一样的)
print(n1.isFinite); //是否有限 false
print(n1.isInfinite); //是否无限
print(n1.isNaN); //是否非数字 true
print(12.isNegative); //是否是负数 false
}
List数组
列表简单来说就是存放着排成一列的数据,可以理解为一个存放数据的容器,列表中的每个数据称为元素,在 Dart 中用 List 表示,数据用 "[]" 括起来,元素之间用 "," 隔开,如果不指定 List 中存放的数据类型的话是可以存放任意类型的数据的,
void main(List<String> args) {
//声明List - 字面量
List l1 = ['a','b','c',1]; //不限制数字类型的一种方式
print(l1);
//泛型(限制元素的类型)
List l2 = <int> [1,2,3]; //<>要加到前面
print(l2);
//通过构造函数的声明方式
// var l3 = new List(); 已经弃用了
var l3 = new List.empty();
print(l3); //[]
var l31 = new List.empty(growable: true);
l31.add(1);
print(l31); //[1]
var l4 = new List.filled(3, 6);
print(l4); //[6, 6, 6]
//扩展运算符
var l5 = [0,...l31,...l4];
print(l5); //[0, 1, 6, 6, 6]
var l6;
var l7 = [7,...?l6]; //不加?会警告,因为null类型不能用于扩展运算符
print(l7); //[7]
//返回列表的长度
print(l1.length); //4
//列表的翻转
print(l1.reversed); //(1, c, b, a) ()里面是一个可迭代的内容,严格意义上来说已经不是列表了
print(l1.reversed.toList()); //[1, c, b, a]
//在制定的位置添加元素
l7.insert(1, 3);
print(l7); //[7, 3]
//清空
l31.clear();
print(l31); //[]
print(l31.isEmpty); //true
//合并元素
List words = ['hello','world'];
print(words.join('-'));//join可以看成split的逆向操作 hello-world
}
list的一些实用功能性函数
void main(List<String> args) {
var nums = [1,2,3];
//forEach
nums.forEach((element) {
print(element);
});
//map
var newNums1 = nums.map((e) => e * e ); //这里的箭头函数后面会介绍到
print(newNums1); //(1, 4, 9)
var newNums2 = nums.map((e){
return e * e;
});
print(newNums2.toList()); //[1, 4, 9]
bool isOdd(n) => n % 2 ==1;
bool isEven(n){
return n % 2 ==0;
}
//where筛选出符合条件的元素,可以用map替代
var oddNum = nums.where(isOdd);
print(oddNum); //(1, 3)
//返回布尔值:有任意一个满足条件
print(nums.any(isOdd)); //true
print(nums.every(isEven)); //false
var pairs = [[1,2],[3,4]];
//expand条件降阶函数
var flattened = pairs.expand((element) => element);
print(flattened); //(1, 2, 3, 4)
//fold函数,类似js的reduce
int result = nums.fold(0, (previousValue, element) => previousValue + element);
print(result); //6
}
Set集合
- Set是一个无序的,元素唯一的集合。要注意它无法通过下标取值。
void main(List<String> args) {
var nums = <int>{1, 2, 3}; //集合的三个性质:确定性、互异性、无序性
print(nums);
//构造函数
var fruits = new Set();
fruits.add('bannana');
fruits.add('apple');
fruits.add('橘子');
print(fruits); //{bannana, apple, 橘子}
print(fruits.toList()); //转成列表 [bannana, apple, 橘子]
//如果列表转换为集合,会去重
List myNums = [1,2,2,3,3,4,5];
print(myNums.toSet()); //{1, 2, 3, 4, 5}
//集合特有的操作
var caocao = new Set();
//addAll批量添加元素
caocao.addAll(['曹仁','夏侯惇','关羽']);
var liubei = new Set();
liubei.addAll(['张飞','关羽','诸葛亮']);
//求交集
print(caocao.intersection(liubei)); //{关羽}
//求并集
print(caocao.union(liubei)); //{曹仁, 夏侯惇, 关羽, 张飞, 诸葛亮}
//求差集
print(caocao.difference(liubei));//{曹仁, 夏侯惇}
//返回第一个元素
print(caocao.first); //曹仁
//返回最后一个元素
print(caocao.last); //关羽
//集合无法通过下标取值
// print(caocao[1]); //报错
}
Map
- Map是一个无序的键值对(key-value)映射。通常被称之为哈希或字典。
- 声明方式
- var map = {key:value1,key2:value2};
- var map = new Map();
- map['key'] = value;
我们通过案例来演示常用api
void main(List<String> args) {
var person = {
'name':'张三',
'age':20
};
print(person); //{name: 张三, age: 20}
//通过构造函数来创建Map
var p = Map();
p['name'] = '李四';
p['age'] = 22;
print(p); //{name: 李四, age: 22}
//访问map的属性
print(p['name']); //李四
//判断Map中的key与value是否存在
print(p.containsKey('name')); //true
print(p.containsValue(22)); //true
//赋值
//如果key不存在,我们才赋值,如果key已经存在了,则不赋值
p.putIfAbsent('gender', () => '男');
p.putIfAbsent('gender', () => '女');
//获取Map中所有的Key
print(p.keys); //(name, age, gender)
//获取Map中所有的value
print(p.values); //(李四, 22, 男)
//根据条件删除map中的值
p.removeWhere((key, value) => key == 'gender');
print(p); //{name: 李四, age: 22}
}
Dart中的一些特殊运算符
除了 + - * / % ?等基本运算符以外,Dart也给我们提供了一些特殊的运算符,如下:
void main(List<String> args) {
//地板除
print(7 ~/ 4); //1.75 向下取整得到1
//类型判断运算符
List list = [];
if(list is List){
print('list is list');
}else{
print('list is not List');
}
print('Hello' is! String); //false;
print(12 is int); //true
//逻辑空运算符??(如果不是空返回表达式前面的,如果是空返回表达式后面的)
print(1 ?? 3); //1
print(null ?? 12); //12
var foo;
print(foo ?? 0); //0
//空赋值语句
var a;
a ??= 3;
print(a); //3
a ??= 6;
print(a); //3
//条件属性运算符(保护可能为空的属性)
var obj;
print(obj?.length); //null
//级联运算符
Set s = new Set();
s..add('a')
..add('b')
..add('c');
print(s); //{a, b, c}
}
Dart中的函数的创建
函数的声明
Dart声明函数跟Java是比较类似而与js不同,它是不需要function关键字的。
void printInfo(){
print("Hello World");
}
//返回值要与函数声明的类型一直
int getNum(){
return 1;
}
void main(List<String> args) {
printInfo(); //调用函数
print(getNum());
}
箭头函数(lamda函数)
- Dart中的箭头函数,函数体只能写一行,不能带有结束的分号。
- Dart中的箭头函数,只是函数的一种简写形式(不会修改this指向)
- Dart中的箭头函数如果参数只有一个,是不能省略()的,这和js不一样
void main(List<String> args) {
List fruits = ['apple','banaana','orange'];
fruits.forEach((element) => print(element));
}
匿名函数
所谓匿名函数就是让一个变量接收一个函数。
void main(List<String> args) {
var myPrint = (value) => print(value);
myPrint(12);
}
立即执行函数
void main(List<String> args) {
//立即执行函数
((int n){
print(n);
})(17);
}
Dart中函数参数的问题
可选参数与命名参数
代码1 必填参数(如果不传参数就会报错)
void main(List<String> args) {
String userInfo(String name){
//必填参数
return '你好$name';
}
String name = userInfo('lebro');
print(name);
}
代码2 可选参数,格式为[类型 变量 = 默认值]
void main(List<String> args) {
//可选参数
String userInfo(String name,[int age = 10]){ //[类型 变量 = 默认值]
return '你好我是$name,我的年龄是$age';
}
String name1 = userInfo('张三');
String name2 = userInfo('李四',20);
print(name1);
print(name2);
}
代码3 命名参数 格式为 {类型 变量 = 默认值} ,与可选参数不同的是,命名参数调用函数的时候必须以键值对的形式跟上变量名和值。
void main(List<String> args) {
//可选参数
String userInfo(String name,{int age = 10}){ //[类型 变量 = 默认值]
return '你好我是$name,我的年龄是$age';
}
String name1 = userInfo('张三');
String name2 = userInfo('李四',age:21);
print(name1);
print(name2);
}
Dart函数的闭包
- Dart中闭包的方式与JS完全一致。它有两个好处,一个是能重用变量,第二个是能保护变量不被污染。
- 闭包的实现原理:外层函数被调用后,外层函数的作用域对象(AO)被内层函数应用者,导致外层函数的作用域对象无法释放,从而形成闭包。
作用域
我们只要看这个图就明白了,里层函数能够访问外层函数的变量,但是翻过来不可以,外层函数访问不到里层函数的变量。
var globalNum = 100;
void main(List<String> args) {
printInfo(){
var localNum = 10;
print(localNum); //10
print(globalNum); //100
}
print(localNum); //访问不了,会报错
printInfo();
}
闭包案例
void main(List<String> args) {
parent(){
var money = 1000;
return (){
money -= 100;
print(money);
};
}
var p = parent();
p();
}
这里由于一直要用到money这个变量,所以内存中的指针并不会移除,变量能够一直被存储着。不过闭包也会带来内存泄漏的问题,如果我们滥用闭包会对代码的性能产生一些影响。
异步函数
- Javascript中,异步函数调用Promise来实现异步。或者也可以用async与await函数,async函数返回一个Promise。await用于等待Promise。
- Dart中,异步调用通过Future来实现,async函数返回一个Futrue,await用于等待Future。
import 'package:http/http.dart' as http;
import 'dart:convert';
// https://httpbin.org/ip 返回ip地址
Future getIPAddress(){
final url = 'https://httpbin.org/ip';
return http.get(url).then((response){
print(response.body);
String ip = jsonDecode(response.body)['origin'];
print(ip);
});
}
void main(List<String> args) {
//调用getIPAdress
getIPAddress()
.then((ip) => print(ip))
.catchError((error) => print(error));
}
import 'package:http/http.dart' as http;
import 'dart:convert';
// https://httpbin.org/ip 返回ip地址
Future getIPAddress() async{
final url = 'https://httpbin.org/ip';
final response = await http.get(url);
print(response.body);
String ip = jsonDecode(response.body)['origin'];
print(ip);
}
void main (List<String> args) async {
//调用getIPAdress
try {
final ip = await getIPAddress();
print(ip);
} catch (e) {
print(e);
}
}