Dart语言语法一文通

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比较

4.可以使用 https://dartpad.cn/上的在线编辑器在线运行测试脚本。
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试一试,出现下述内容表示下载成功。

image
2.配置VSCODE

安装dart语言支持

image

安装code runner

image

第三部分 基本语法

一、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进行修饰,那么可以保证同一个参数,创建出来的对象是相同的

p1,p2是同一个对象

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这个抽象的类,这个类是无法实例化的,但是CircleRact都继承于它.所以能够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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值