美文网首页
Flutter学习(三)Dart语法汇总

Flutter学习(三)Dart语法汇总

作者: yanhooIT | 来源:发表于2020-03-26 12:14 被阅读0次

内部团队学习,以简单直接为主

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);
}

数据类型

  • 占位符:${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';

相关文章

网友评论

      本文标题:Flutter学习(三)Dart语法汇总

      本文链接:https://www.haomeiwen.com/subject/jkequhtx.html