Dart是谷歌的皇太子,更有Flutter等大臣辅佐。继位正统,拳打JS,脚踢Java是分分钟的事情. 所以大家都应该“奉旨”学习Dart
本文分以下几个部分: 一、Dart整体思想 二、Dart环境搭建 三、基本语法
学习dart好去处:
Dart 编程语言主页www.dartdoc.cn
dart在线编辑器https://dartpad.cn/
小贴士:
- runtimetype属性 代表了变量的类型
- 判断类型还可以用
is
关键词 如:if(str1 is Sting){}
- 异常处理:
try{}
catch(err){
}
第一部分:Dart整体思想
1.Dart是一种面向对象的语言,具有C语言风格的语法,可以选择将它编译成JavaScript。;
2.它支持各种编程辅助工具,如:接口,类,集合,泛型和可选类型。
3.Dart与JS比较
5.dart程序源文件通常以扩展名.dart命名。
6.学习dart好去处:
Dart 编程语言主页 www.dartdoc.cn
7.dart是强数据类型语言
8.Dart程序代码由以下组成* 变量和运算符
- 类
- 函数
- 表达式和编程构造
- 决策和循环结构
- 注解
- 库和包
- 类型定义
- 数据结构 - 集合/泛型
9.Dart优势: - Dart可基于AOT(Ahead Of Time)编译,即编译成平台的本地代码,运行性能高。
- Dart也可基于JIT(Just In Time)编译,编译快速,可热加载,使开发周期加倍提升(Flutter亚秒级有状态热重载)
- Dart可以更轻松地创建以60fps运行的流畅动画和转场。Dart在没有锁的情况下进行对象分配和垃圾回收
- Dart语法结合Java与JavaScript语法特点,几乎没有令人不适的怪异语法,使Java程序员倍感亲切,快速上手
第二部分 环境搭建
1.下载dart
https://gekorm.com/dart-windows/gekorm.com
傻瓜化安装。自动配置环境变量。
用CMD试一试,出现下述内容表示下载成功。
2.配置VSCODE
安装dart语言支持
安装code runner
第三部分 基本语法
一、hello world
创建一个test.dart
void main() { print("hello world"); }
二. 重要概念
- 一切变量都是对象
- 对象是类的实例,一切实例继承与Object
- 是强类型语言但支持推断
- 不想指定类型可以指定dynamic
- 支持泛型:list<int>或list<dynamic>
- 支持定成函数 类方法 实例方法和嵌套函数
- 支持顶层变量 类变量 实例变量和局部变量
- 以 _打头的变量为私有,只有在库内使用
- 代码问题可以分为warning和error warning不会阻止程序运行,error会
- dart没有非空既真的判断方式
if(0){}
这种是不行的
三. 变量
- 如果变量不可变可以定义为:const或者final
两者的差别是const是必须在编译之前就确定的 - 一旦一个变量被赋予了某个类型,是不能通过重新定义其他类型数据来改变类型的
- 但是,如果给变量声明为dynamic, 是可以变化的
- 查看变量类型: 所有的变量都有一个属性叫runtimeType
var str='hello';
print(str.runtimeType); //String
四.数据类型
1.数据类型转换
- 字符串转整形:
var a=int.parse('1');
- 字符串转浮点型:
var a=double.parse('1');
- 转字符串:
var str=1.toString();
- 浮点型转字符串保留n位小数
var str=1.1244541.toStringAsFixed(2);
2.字符串
- 字符串拼接
//可以用 +
str='hello '+'world';
//也可以用''' '''包裹换行文字
str2='''白日依山尽,
黄河入海流''';
- 字符串插值用$
print('hello $name');
//如果会引起歧义,则用{}包裹
print('hello ${a + b}');
//{}里面还可以调用方法
print('hello ${name.toUpperCase()}');
3. 集合
- list : 常见的列表
- set : 集合.元素不可重复,没有顺序
- map : 键值对
list类型
List<String> names=['kobe','james','quinn'];
set类型
Set<int> nums={101,102,111,114}
//set可以用于对List去重,如:
List<String> names2=List.from(Set.from(names));
Map<String,dynamic> info={
'name':'lili',
'age':18
}
4. 集合方法
①. elementAt(n) //列表中的第n个元素
void main() {
List<int> nums =[123,122,333];
print(nums.elementAt(2));
}
②. isEmpty 为空判断 isNotEmpty 非空
可以判断字符串 集合是否为空
③. isNan NAN判断
可以判断数值是否为 NAN
④. 添加元素 add addAll
list.add(元素)
//添加多个元素
list.addAll([元素1,...])
⑤.元素的索引 indexOf
list.indexOf(元素)
如果查找不到返回-1
⑥. 删除元素 remove removeAt
list.remove(元素)
list.removeAt(索引)
⑦.修改元素 fillRange
list.fillRange(起始位置,结束位置,修改内容)
⑧. 插入数据 insert insertAll
list.insert(索引,值)
list.insertAll(索引,[值1,值2...])
⑨.切割字符串 拼接字符串
str.split(切割符) //会转为数组
str.join(合并符) //会转为字符串
⑩. 集合间互相转化
list.toSet() //返回一个set
set.toList() //返回一个List
①①. Map方法
1.增加数据
m1.addAll({
键:值
})
2.删除数据
m1.remove(键)
3.查找有没有某个值
m1.containsValue(值)
5. 集合遍历方法
①. map方法
list.map((value){
return value的处理
})
②. where 过滤方法
List list1=[1,2,3,4,5,6,7];
list1.where((value){
return value>5;
})
//返回一个数组
③. any 有没有满足条件 //返回布尔
list1.any((value){
return value>5;
})
④. every 每一个都满足条件 //返回布尔
五 函数
1.函数的定义
返回类型 函数名(参1类型 参1,参2类型 参2){
//函数体
}
- 匿名函数 (){}
name.forEach((item){
print(item);
});
箭头函数 ()=>xxx 仅限执行一行代码
name.forEach((item)=>print(item));
//默认return执行一行代码的结果
2.必传参数和可选参数
可选参数分两种
- 位置可选参数 用[]包裹 根据位置传递
void printInfo(String name,[int age,double score]){
print('$name $age $score');
}
//以下的三种调用都不报错
printInfo('kobe');
printInfo('kobe',18);
printInfo('kobe',18,99.9);
- 命名可选参数 用{}包裹 必须命名传值
void printInfo(String name,{int age,double score}){
print('$name $age $score');
}
printInfo('kobe');
printInfo('kobe',age:18);
printInfo('kobe',score:99.9);
printInfo('kobe',age:18,score:99.9);
3.参数默认值
默认值只能给可选参数~
void printInfo(String name,[int age=18,double score=60]){
print('$name $age $score');
}
4. 函数作为第一公民?
函数可以作为参数,也可以作为返回值(同JavaScript)
5. 返回值默认为null
6. 泛型函数
void main() {
List<int> nums =[123,122,333];
print(getFirst(nums));
List<String> strs =['kobe','james','paul'];
print(getFirst(strs));
}
T getFirst<T>(List<T> list) {
return list[0];
}
六. 运算符
- /是真除法
- ~/才是地板除
- ??= : 当变量为null时才能赋值成功
var name=null;
name ??= 'Kobe'; //此时name为Kobe
name ??= 'James' //赋值失败,name还是Kobe
-
值1??值2
:赋值1, 如果值1为null就赋值2
var value1=null;
var value2=10;
var a= value1 ?? value2; //a=10
-
级联运算符 : 方便的一次性调用属性和方法
三元运算符
var result= 条件 ? 成立返回值:不成立返回值
第四部分 类和对象
一. 类的构造函数
1. 无参的构造函数
final p = Person();
p.name = "zhangsan";
p.age = 18;
print('${p.name} ${p.age}');
}
class Person {
String name;
int age;
void eating() {
print('chi');
}
}
2.有参的构造函数
对象内部有了构造函数,就会顶替默认的构造函数
构造函数的参数是可以设默认值或者可选的
void main() {
final p = Person(name:'zhangsan',age:18);
print('${p.name} ${p.age}');
}
class Person {
String name;
int age;
Person({String name,int age}){ //{}包裹就是可选参数
this.name=name;
this.age=age;
}
void eating() {
print('chi');
}
}
3. 语法糖写法
void main() {
final p = Person(name:'zhangsan',age:18);
print('${p.name} ${p.age}');
}
class Person {
String name;
int age;
Person({this.name,this.age}); //把this.name=name缩写了
void eating() {
print('chi');
}
}
4.增加命名构造函数
void main() {
void main() {
Map<String, dynamic> p1 = {"name": "kobe", 'age': 30};
final p2 = Person.fromMap(p1);
print('${p2.name} ${p2.age}');
final p = Person(name: "lili", age: 18);
print('${p.name} ${p.age}');
}
class Person {
String name;
int age;
Person({this.name, this.age});
Person.fromMap(Map<String, dynamic> map) { //命名构造函数
this.name = map['name'];
this.age = map['age'];
}
void eating() {
print('chi');
}
}
5. 重写对象里的toString()方法
我们在对象中重写了toString()方法,这样我们再print(对象实例)时,就会调用这个方法.
void main() {
final r1 = Ract(20, 15);
print(r1);
}
class Ract {
double width;
double height;
double area;
Ract(this.width, this.height) {
this.area = width * height;
}
@override
String toString() {
return 'width:$width height:$height area:$area';
}
}
6. 初始化列表
上面的例子,我们可以用初始化列表来简化构造函数
void main() {
final r1 = Ract(20, 15);
print(r1);
}
class Ract {
double width;
double height;
double area;
Ract(this.width, this.height):area = width * height;
@override
String toString() {
return 'width:$width height:$height area:$area';
}
}
7. 构造方法重定向
从一个构造函数中调用另一个构造函数
void main() {
final p = Person.fromName("lili");
print('${p.name} ${p.age}');
}
class Person {
String name;
int age;
Person(this.name,this.age);
Person.fromName(String name):this(name,18);
//下面的构造方法后面用:初始化列表时,ding
}
8. 常量构造方法
如果一个构造方法用const
进行修饰,那么可以保证同一个参数,创建出来的对象是相同的
9. 类的继承和方法的重写 extends
class Animal{
int age;
void eat(){
print('EAT...');
}
}
class Person extends Animal {
String name;
@override
void eat(){
print('have a meal~');
}
}
10.子类继承父类的属性
class Animal{
int age;
Animal(this.age);
void eat(){
print('EAT...');
}
}
class Person extends Animal {
String name;
Person(this.name,int age):super(age);
}
11. 抽象类 abstract
- 抽象类不能被实例化
- 抽象类可以定义抽象方法 只有定义 没有实现
- 最主要的作用在于多态
- 抽象类的子类必须实现抽象类里的方法
void main() {
final c1 = Circle(10);
calcuArea(c1);
final r1 = Ract(10, 20);
calcuArea(r1);
}
abstract class Shape { //抽象类
getArea(); //抽象方法
}
class Circle extends Shape {
double r;
Circle(this.r);
double getArea() {
return r * r * 3.14;
}
}
class Ract extends Shape {
double width, height;
Ract(this.width, this.height);
double getArea() {
return width * height;
}
}
void calcuArea(Shape thing) { //这个方法里传的是shape
print(thing.getArea());
}
上例中,我们有一个计算面积的方法calcuArea
,我们给它传参时,给他传入的是shape
这个抽象的类,这个类是无法实例化的,但是Circle
和Ract
都继承于它.所以能够calcuArea
能够调用到它们各自的getArea方法
12. 隐式接口 implements
- 在dart是没有接口的定义的
- 在默认情况下所有的类都是接口
- 实现时,接口里所有的方法必须都被实现
class Runner {
void running() {
print('running.....');
}
}
class Person implements Runner { //此时,runner就被作为一个接口来实现了
@override
void running() {
print('preson is running....');
}
}
多个继承?
dart里面的类是单继承的, 这个抽象类的概念有些相悖,
如果一个类为了调用某个函数需要继承抽象类1,同时,为了用另一个函数又要继承抽象类2.这种情况是无法实现的,除非使用mixin将其中一个抽象类当作接口类来调用.
13. mixin混入
void main() {
final p1=Person();
p1.running();
p1.swimming();
}
mixin Runner {
void running() {
print('running.....');
}
}
mixin Swimer {
void swimming(){
print('swimming......');
}
}
class Person with Runner ,Swimer {}
14 类的成员和方法
前面的都是对象级别的方法和属性, 有时我们也需要定义类级别的成员和方法
在dart中使用static
来修饰定义.
15. 枚举类型
enum Colors{
red,
green,
blue
}
16. 泛型类
void main() {
Location l1 = Location <int>(10,20);
Location l2 = Location <double>(10.1,20.2);
}
class Location<T>{
T x;
T y;
Location(this.x,this.y);
}
第五部分 库
dart中每个dart文件都可以称之为一个库,即使你没有使用library
来声明.
1.库的导入
(1). 导入标准库
- dart:io
- dart:html
- dart:html
- dart:math
- dart:core
import dart:io ;
(2) 导入自己的库
import '库所在的url';
(3) 第三方库
dart有一个包管理工具 pub,导入其中的库则需要使用前提package
import 'package:flutter/material.dart';
(4). 导入时起别名
import 'lib/student.dart' as Stu;
(5). 库的拆分
比如有一个库,文件内容太多,那么可以对其进行拆分:
//在总文件 utils.dart中
export 'mathUtils.dart'
export 'dateUtils.dart'
第六部分 异步操作
Dart中的异步操作主要使用Future以及async、await。
1. Future
main(List<String> args) {
print("main function start");
// 使用变量接收getNetworkData返回的future
var future = getNetworkData();
// 当future实例有返回结果时,会自动回调then中传入的函数
// 该函数会被放入到事件循环中,被执行
future.then((value) {
print(value);
});
print(future);
print("main function end");
}
2. await、async
await、async是什么呢?
它们可以让我们用同步的代码格式,去实现异步的调用过程。
并且,通常一个async的函数会返回一个Future
Future<String> getNetworkData() async {
var result = await Future.delayed(Duration(seconds: 3), () {
return "network data";
});
return "请求到的数据:" + result;
}