内部团队学习,以简单直接为主
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();
- const声明常量
- const在赋值时, 赋值的内容必须是在
编译期
就确定下来的
- 示范代码
const name = 'yanhoo';
// 再次赋值是不允许的
// const name = 'yety';
- 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);
}
数据类型
// 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 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是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
- 循环操作
- 基本的for循环
- for in遍历List和Set类型
- while和do-while和其他语言一致
- break和continue用法也是一致
- switch-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';
网友评论