Flutter学习(三)Dart语法汇总
2020-03-26 本文已影响0人
yanhooIT
内部团队学习,以简单直接为主
Dart差异化语法说明
- 这里是从一个有1-2年移动端开发经验的开发者视角总结的Dart语法
- 这里只会说一些差异化的语法,类似的语法就不在说了
学习工具配置
- 我在学习Dart语法选择了VSCode这个工具,因为他比较轻量级,首先在这里下载VSCode
- 安装插件,我安装了
Flutter、Dart、Code Runner、Chinese以及一个Theme
,如下图 VSCode插件安装
在VSCode中添加dart文件
- 直接新建
xxx.dart
文件即可 - 每个dart文件中必须显式添加入口函数
main函数
入口main函数
- 新建
helloDart.dart
文件 - 添加
main函数
,代码如下:
main(List<String> args) {
// dart打印用print函数
print('Hello Dart');
}
- 在终端执行
dart helloDart.dart
,就能看到Hello Dart
的结果了
定义变量
明确声明(Explicit)
- 格式:
变量类型 变量名称 = 赋值;
- 定义的变量可以修改值, 但是不能赋值其他类型
- 代码示范
String name = "yanhoo";
// 可以随时被修改
name = "yety";
// 不允许赋值其他类型
// name = 19;
类型推导(Type Inference)
- 格式:
var/dynamic/const/final 变量名称 = 赋值;
- var
- 类型推导的方式虽然没有明确的指定变量的类型, 但是变量是有自己的
明确的类型
- 代码示范
var age = 20; age = 30; // 不可以将String赋值给一个int类型 // age = "abc"; // runtimeType用于获取变量当前的类型 print(age.runtimeType);
- 类型推导的方式虽然没有明确的指定变量的类型, 但是变量是有自己的
- dynamic
- 类型动态化,开发中不建议使用,会存在隐患
- 示例代码
dynamic name = 'yanhoo'; print(name.runtimeType);// String name = 18; print(name.runtimeType);// int
- final声明的常量
- final在赋值时, 可以
运行时
动态获取, 比如赋值一个函数 - final一旦被赋值后就有确定的结果, 就不允许再次赋值
- 示范代码
final time = DateTime.now(); // 再次赋值是不允许的 // final time = DateTime.now();
- final在赋值时, 可以
- const声明常量
- const在赋值时, 赋值的内容必须是在
编译期
就确定下来的 - 示范代码
const name = 'yanhoo'; // 再次赋值是不允许的 // const name = 'yety';
- const在赋值时, 赋值的内容必须是在
- const声明常量构造函数
main(List<String> args) {
// 这样就可以赋值给const修饰的变量
const p1 = Person("yanhoo");
const p2 = Person("yanhoo");
const p3 = Person("yety");
print(identical(p1, p2));// true
print(identical(p2, p3));// false
}
class Person {
// 常量构造函数中的成员变量必须使用final修饰
final String name;
// 常量构造函数
const Person(this.name);
}
数据类型
- 占位符:
${expression}
(如果表达式是一个标识符, 那么{}可以省略),用于字符串、其他变量以及表达式的拼接 - 数值类型
- 对于数值来说,我们也不用关心它是否有符号,以及数据的宽度和精度等问题。只要记着整数用int,浮点数用double就行了,Dart中的int和double可表示的范围并不是固定的,它取决于运行Dart的平台
- 字符串和数字之间的转化
// 1.字符串转数字 var one = int.parse('111'); var two = double.parse('12.22'); print('${one} ${one.runtimeType}'); // 111 int print('${two} ${two.runtimeType}'); // 12.22 double // 2.数字转字符串 var num1 = 123; var num2 = 123.456; var num1Str = num1.toString(); var num2Str = num2.toString(); var num2StrD = num2.toStringAsFixed(2); // 保留两位小数 print('${num1Str} ${num1Str.runtimeType}'); // 123 String print('${num2Str} ${num2Str.runtimeType}'); // 123.456 String print('${num2StrD} ${num2StrD.runtimeType}'); // 123.46 String
- 布尔类型:Dart中不能判断非0即真, 或者非空即真,你必须给出明确的布尔值,其他也没什么好说的
- 字符串类型
// 1、Dart字符串是UTF-16编码单元的序列。您可以使用单引号或双引号创建一个字符串
var s1 = 'Hello World';
var s2 = "Hello Dart";
var s3 = 'Hello\'Fullter';
var s4 = "Hello'Fullter";
// 2、可以使用三个单引号或者双引号表示多行字符串
var message1 = '''
哈哈哈
呵呵呵
嘿嘿嘿''';
- 集合类型:
List / Set / Map
,这个也没啥好说的,下面用代码的方式说一下各自的定义和一些基本用法
// ----------------- List定义 -----------------
// 1.使用类型推导定义
var letters = ['a', 'b', 'c', 'd'];
print('$letters ${letters.runtimeType}');
// 2.明确指定类型
List<int> numbers = [1, 2, 3, 4];
print('$numbers ${numbers.runtimeType}');
// Set和List最大的两个不同就是:Set是无序的,并且元素是不重复的
// ----------------- Set定义 -----------------
// 1.使用类型推导定义
var lettersSet = {'a', 'b', 'c', 'd'};
print('$lettersSet ${lettersSet.runtimeType}');
// 2.明确指定类型
Set<int> numbersSet = {1, 2, 3, 4};
print('$numbersSet ${numbersSet.runtimeType}');
// ----------------- Map定义 -----------------
// 1.使用类型推导定义
var infoMap1 = {'name': 'xxx', 'age': 18};
print('$infoMap1 ${infoMap1.runtimeType}');
// 2.明确指定类型
Map<String, Object> infoMap2 = {'height': 1.88, 'address': '北京市'};
print('$infoMap2 ${infoMap2.runtimeType}');
- 集合的常见操作,直接上代码
// ----------------- List 和 Set的操作 -----------------
// 获取集合的长度
print(lettersList.length);
print(lettersSet.length);
print(infoMap.length);
// 添加/删除/包含元素
numbersList.add(5);
numbersSet.add(5);
print('$numbersList $numbersSet');
numbersList.remove(1);
numbersSet.remove(1);
print('$numbersList $numbersSet');
print(numbersList.contains(2));
print(numbersSet.contains(2));
// List由于是有序的,所以可以根据index删除元素
numbersList.removeAt(3);
print('$numbersList');
// ----------------- Map的操作 -----------------
// 1.根据key获取value
print(infoMap1['name']);
// 2.获取所有的entries
print('${infoMap1.entries} ${infoMap1.entries.runtimeType}'); // (MapEntry(name: xxx), MapEntry(age: 18)) MappedIterable<String, MapEntry<String, Object>>
// 3.获取所有的keys
print('${infoMap1.keys} ${infoMap1.keys.runtimeType}'); // (name, age) _CompactIterable<String>
// 4.获取所有的values
print('${infoMap1.values} ${infoMap1.values.runtimeType}'); // (xxx, 18) _CompactIterable<Object>
// 5.判断是否包含某个key或者value
print('${infoMap1.containsKey('age')} ${infoMap1.containsValue(18)}'); // true true
// 6.根据key删除元素
infoMap1.remove('age');
print('${infoMap1}'); // {name: xxx}
函数
概述
- Dart是一种真正的面向对象语言,所以函数也是对象,也有类型,类型为
Function
- 函数可以
作为变量定义
或者作为其他函数的参数或者返回值
函数的定义
返回值 函数的名称(参数列表) {
// coding...
return 返回值;
}
// 示例
int sum(int num1, int num2) {
return num1 + num2;
}
// 也可以这么写(不推荐)
sum(num1, num2) {
return num1 + num2;
}
// 如果函数体只有一句,可以使用箭头函数
// 箭头函数不允许以分号结尾,上面的可以这样写
sum(int num1, int num2) => num1 + num2
函数的参数
- 必填参数,如下:
int sum(int num1, int num2) {
return num1 + num2;
}
- 可选参数:
命名可选参数
和位置可选参数
,个人更加偏好命名可选参数- 命名可选参数定义方式:
{
param1, param2, ...}
// 命名可选参数 printInfo1(String name, {int age, double height}) { print('name=$name age=$age height=$height'); } // 调用printInfo1函数 printInfo1('xxx'); // name=xxx age=null height=null printInfo1('xxx', age: 18); // name=xxx age=18 height=null printInfo1('xxx', age: 18, height: 1.88); // name=xxx age=18 height=1.88 // 顺序调换也可以 printInfo1('xxx', height: 2.88, age: 28); // name=xxx age=28 height=2.88 printInfo1('xxx', height: 1.88); // name=xxx age=null height=1.88
- 位置可选参数定义方式:
[
param1, param2, ...]
// 定义位置可选参数 printInfo2(String name, [int age, double height]) { print('name=$name age=$age height=$height'); } // 调用printInfo2函数 printInfo2('xxx'); // name=xxx age=null height=null printInfo2('xxx', 18); // name=xxx age=18 height=null printInfo2('xxx', 18, 1.88); // name=xxx age=18 height=1.88
- 命名可选参数定义方式:
- 可选参数可以设置默认值
// 可选参数的默认值
printInfo4(String name, {int age = 18, double height=1.88}) {
print('name=$name age=$age height=$height');
}
- 函数可以
作为变量定义
或者作为其他函数的参数或者返回值
main(List<String> args) {
// 1.将函数赋值给一个变量
var bar = foo;
print(bar);
// 2.将函数作为另一个函数的参数
test(foo);
// 3.将函数作为另一个函数的返回值
var func = getFunc();
func('kobe');
}
// 1.定义一个函数
foo(String name) {
print('传入的name:$name');
}
// 2.将函数作为另外一个函数的参数
test(Function func) {
func('kobe');
}
// 3.将函数作为另一个函数的返回值
getFunc() {
return foo;
}
- 匿名函数
main(List<String> args) {
// 1.定义数组
var movies = ['少年', '你的答案', '缘字书', '不谓侠'];
// 2.使用forEach遍历: 有名字的函数
printElement(item) {
print(item);
}
movies.forEach(printElement);
// 3.使用forEach遍历: 匿名函数
movies.forEach((item) {
print(item);
});
movies.forEach((item) => print(item));
}
- 通过
typedef
定义个函数对象,增加可读性
typedef Calculate = int Function(int num1, int num2);
void test(Calculate calc) {
var result = calc(20, 30);
print(result);
}
运算符
- 除法、整除、取模运算
var num = 7;
print(num / 3); // 除法操作, 结果2.3333..
print(num ~/ 3); // 整除操作, 结果2;
print(num % 3); // 取余/模操作, 结果1;
-
??=:
运算符
// 1 当原来的变量有值时, 那么??=不执行
var name = "kobe";
name ??= "lilei";
print(name);// kobe
// 2 原来的变量为null, 那么将值赋值给这个变量
var name1 = null;
name1 ??= "lilei";
print(name1);// lilei
- 条件运算符:
expr1 ?? expr2
// 如果expr1是null,则返回expr2的结果;
// 如果expr1不是null,直接使用expr1的结果
var temp = 'yanhoo';
var name = temp ?? 'kobe';
print(name);// yanhoo
var temp1 = null;
var name1 = temp1 ?? 'kobe';
print(name1);// kobe
- 级联语法:
..
main(List<String> args) {
// 分开调用
final p1 = Person();
p1.name = 'kobe';
p1.run();
p1.eat();
p1.swim();
// 通过级联语法
final p2 = Person()
..name = "kobe"
..run()
..eat()
..swim();
}
// 自定义类
class Person {
String name;
void run() {
print("${name} is running");
}
void eat() {
print("${name} is eating");
}
void swim() {
print("${name} is swimming");
}
}
流程控制
- if和else
- 注意:这里
没有非0即真,非空即真
- 注意:这里
- 循环操作
- 基本的for循环
- for in遍历List和Set类型
- while和do-while和其他语言一致
- break和continue用法也是一致
- switch-case
- 相对于OC,case语句后支持字符串
泛型
- 泛型的作用:我们在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样。但我们没有办法,只能分别写多个方法来处理不同的数据类型。这个时候,那么问题来了,有没有一种办法,用同一个方法来处理传入不同种类型参数的办法呢?泛型的出现就是专门来解决这个问题的。
- List和Map的泛型
// ------------------- 创建List的方式 -------------------
var names1 = ['why', 'kobe', 'james', 111];
print(names1.runtimeType); // List<Object>
// 限制类型
var names2 = <String>['why', 'kobe', 'james', 111]; // 最后一个报错
List<String> names3 = ['why', 'kobe', 'james', 111]; // 最后一个报错
// ------------------- 创建Map的方式 -------------------
var infos1 = {1: 'one', 'name': 'why', 'age': 18};
print(infos1.runtimeType); // _InternalLinkedHashMap<Object, Object>
// 对类型进行显示
Map<String, String> infos2 = {'name': 'why', 'age': 18}; // 18不能放在value中
var infos3 = <String, String>{'name': 'why', 'age': 18}; // 18不能放在value中
- 定义泛型类
main(List<String> args) {
Location l2 = Location<int>(10, 20);
print(l2.x.runtimeType); // int
Location l3 = Location<String>('aaa', 'bbb');
print(l3.x.runtimeType); // String
}
}
class Location<T> {
T x;
T y;
Location(this.x, this.y);
}
- 限制泛型的范围
main(List<String> args) {
Location l2 = Location<int>(10, 20);
print(l2.x.runtimeType);
// 错误的写法, 类型必须继承自num
Location l3 = Location<String>('aaa', 'bbb');
print(l3.x.runtimeType);
}
// 限制泛型类型为继承自num的类型
class Location<T extends num> {
T x;
T y;
Location(this.x, this.y);
}
- 定义泛型方法
main(List<String> args) {
var names = ['Jordan', 'kobe'];
var first = getFirst(names);
print('$first ${first.runtimeType}'); // Jordan String
}
T getFirst<T>(List<T> ts) {
return ts[0];
}
库的使用
- Dart中任何一个dart文件都是一个库,即使你没有用关键字library声明
- 通常在定义库时,我们可以使用library关键字给库起一个名字
library math;
- 库的导入
// dart:前缀表示Dart的标准库,如dart:io、dart:html、dart:math
import 'dart:io';
//当然,你也可以用相对路径或绝对路径的dart文件来引用
import 'lib/student/student.dart';
//Pub包管理系统中有很多功能强大、实用的库,可以使用前缀 package:
import 'package:flutter/material.dart';
// 希望只导入库中某些内容,或者刻意隐藏库里面某些内容,可以使用show和hide关键字(这个功能个人感觉好鸡肋)
import 'lib/student/student.dart' show Student, Person;
import 'lib/student/student.dart' hide Person;
-
as关键字
的作用:当各个库有命名冲突的时候,可以使用as关键字来定义一个命名空间用于区分
import 'lib/student/student.dart' as Stu;
// Stu.Student使用指定命名空间里的类
Stu.Student s = new Stu.Student();
-
export
关键字 - 如果一个库文件很大,可以拆分成多个库,使用export关键字在某个库文件中集中导入
mathUtils.dart
dateUtils.dart
可以新建一个utils.dart文件,并在文件中集中导入
export 'mathUtils.dart';
export 'dateUtils.dart';
// 使用
import "lib/utils.dart";
- 补充:在Dart中如果有些方法不想被除当前库文件以外访问可以使用
下划线
// 这样定义的函数,当前库以外的就不能访问
int _min(int num1, int num2) {
return num1 > num2 ? num2: num1;
}
- 使用第三方的库文件
- 首先创建
pubspec.yaml
,在文件中导入你要引用的三方库
name: 自己去个有意义的名字
description: 描述信息
dependencies:
http: ^0.12.0+4
- 到pub.dev(
无需科学上网
)下载你要引用的三方库 - 比如我搜索http,然后点击Installing按照说明进行引入 安装库
- cd到
.yaml
文件所在的文件夹,在终端里执行pub get
命令 - 导入文件,三方库都是以
package:
开头
import 'package:http/http.dart';