Dart学习笔记

安装步骤

  1. ANDROID_HOME 安卓SDK的位置

  2. ANDROID_SDK_HOME 安卓模拟器avd的位置

  3. GRADLE_USER_HOME .gradle的位置

  4. 将flutter>bin配置成环境变量

Dart

Dart是谷歌开发的,类型安全的,面向对象的编程语言,被应用与web、服务器、移动应用和物联网等领域

dart中,所有内容都是对象。

dart生态

变量

  • 明确指定类型:int String
  • 不明确类型:var age = 18; dynamic age = 18;
  • 大小写敏感
  • 变量的默认值是null (js变量的默认值是undefined
  • Dart变量的值不会进行隐式转换

常量

常量就是值不可变的变量

  • const age = 18;
  • final age = 18;

const和finale的区别

  • const time = DateTime.now(); 报错,无法将运行时的值分配给const变
  • final time = DateTime.now();` 将运行时的值分配给final变量

数据类型

  1. Number
    • num数字类型(可是是整数,也可以是小数)num n;
      • int 表示整数(必须是整数)
      • double表示浮点数(可以是整数,也可以是小数)
  2. String
    • 单双引号都可以
    • 三个引号可以生命包含换行符(回车)的字符串
  3. Boolean
    • bool
  4. List(数组)
    • List list = []; 不限制数据类型
    • List list = <int>[];限制元素类型
    • 构造函数
    • 扩展操作符...
  5. Set
    • 无序,元素唯一的集合
    • {}
    • 无法通过下标取值
    • 可以求交集、并集
  6. Map
    • var map = new Map();
    • var map = { key:value};
  7. 其他
    • Runes https://copychar.cc/
    • Symbol
      • #开头来表示的标识符
    • dynamic 动态数据类型

类型转换

num n1 = 3.3;
n1.toString();

遍历List

  • forEach()
    • 遍历列表
  • map()
    • 遍历并处理元素,然后生成新的列表
  • where()
    • 返回满足条件的数据
  • any()
    • 只要有一项满足条件,即返true

运算符

  • 地板除(~/)7~/41.751
  • 类型判断运算符(is|is!) ``
  • 避空运算符(??|??=
  • 条件属性访问(?.
  • 级联运算符(..
    • myObj.myMethod(); 返回myMethod的返回值
    • myObj..myMethod(); 返回myObj的引用
var a;
a ??= 3; // a为空,赋值为3
a ?? 3; // a为空返回3 类似于js得 |

Set s = new Set();
s..add(1)..add(2); // 级联写法

函数

  • 直接声明
  • 箭头函数,此函数体只能写一行且不能带有结束符号。他是函数的一种简写形式。
  • 匿名函数
  • 立即执行函数
// 声明函数,不需要 function 关键字
void printInfo() {
  print('hello,world');
}
// 匿名函数
var myPrint = (val) {
    print(val);
};
// 箭头函数
f.forEach((element) => {print(element)});
// 立即执行函数
  ((int n) {
    print(n);
  })(18);

函数参数

  • 必填参数 参数类型 参数名称。
  • 可选参数 放在必选参数后面,通过中括号包裹。
  • 命名参数 用大括号包裹,调用时命名参数的名称与声明函数中的名称保持一致。
// 可选参数 [int age = 22]
String userInfo(String name, [dynamic age]) {
  return '你好:${name}, 年龄:$age';
}

// 命名参数
String userInfo(String name, {int age = 22}) {
  return '你好:${name}, 年龄:$age';
}
// 调用时,实参和形参一致
String res = userInfo('rain', age: 22);

// 函数参数
var myPrint = (val) {
  print(val);
};
List f = ['苹果', '猕猴桃'];
f.forEach(myPrint); // 这里是函数参数

作用域&闭包

dart中的闭包的实现方式与JS中完全一致。

使用时机:既能重用变量,又保护变量不被污染。

实现原理:外层函数被调用后,外层函数的作用域对象(AO) 被内层函数引用着,导致外层函数的作用域对象无法释放,从而形成闭包

 parent() {
    // 外层函数的作用域并没有释放,会一直在内存中存在
    // 所以money的值被记录了
    var money = 1000;
    print('parent money: $money');
    return () {
      // 内层函数每次调用会开辟自己的作用域
      // 调用完释放作用域
      money -= 100;
      print('money:$money');
    };
  }

  var p = parent();
  p();
  p();
  p();
  // money:900
  // money:800
  // money:700

异步函数

异步调用通过Future实现。

async函数返回一个Future,await用于等待Future

异步函数的文档

import 'package:http/http.dart' as http;
import 'dart:convert';

Future getIpAddress() {
  final url = Uri.parse('https://httpbin.org/ip');
  return http.get(url).then((res) {
    // print(res.body); // 这个body是接口的返回值
    String ip = jsonDecode(res.body)['origin'];
    return ip;
  });
}

void main() {
  getIpAddress().then((ip) => print(ip)).catchError((err) => print(err));
}
Future getIpAddress() async {
  final url = Uri.parse('https://httpbin.org/ip');
  final res = await http.get(url);
  String ip = jsonDecode(res.body)['origin'];
  return ip;
}
void main() {
    final ip = await getIpAddress();
    print(ip);
}

类与对象

类是通过class声明的代码段,包含属性和方法。

对象是类的实例化结果。

class Person{}

构造器(构造函数)

默认构造函数
class Point {
  num x, y;
  // 声明普通构造函数
  Point(num x) {
    print('我是默认构造函数,实例化时第一个被调用');
    this.x = 0;
    y = 0; // Dart中 this 可以省略
  }
}
class Point {
  num x, y;
  Point(this.x, this.y); // 省略函数体直接赋值
}
var p = new Point(11, 2);
p.x; // 11
命名构造函数

在类中使用命名构造器(类名.函数名)实现多个构造器,可以提供额外的清晰度

class Point {
  num x, y;
  Point(this.x, this.y);
  Point.origin() {
    x = 0;
    y = 0;
  }
  // 命名构造函数
  // 函数的命名参数
  Point.fromJson({x: 0, y: 0}) {
    this.x = x;
    this.y = y;
  }
}
void main(List<String> args) {
  // 默认坐标
  Point p1 = new Point.origin(); // 调用命名构造函数
  print(p1.x);

  // 手动坐标
  Point p2 = new Point.fromJson(x: 6, y: 6);
  print(p2.x); // 6
}
常量构造函数

如果类生成的对象不会改变,您可以通过常量构造函数使这些对象成为编译时常量

class ImmutablePoint {
  // 属性必须通过 final 声明
  final num x, y;
  // 常量构造函数,通过const声明
  // 不可以有函数体
  const ImmutablePoint(this.x, this.y);
}
void main() {
  // 当通过new的实例化时。常量构造函数可以当作普通构造函数使用
  var p3 = new ImmutablePoint(1, 2);
  var p4 = new ImmutablePoint(1, 2);
  print(p3 == p4); // false

  // 正确的声明方式 使用const声明
  var p5 = const ImmutablePoint(1, 2);
  var p6 = const ImmutablePoint(1, 2);
  print(p5 == p6); // true
}
工厂构造函数

通过factory 关键字声明,工厂函数不会自动生成实例,而是通过代码来决定返回的实例。

  • class里不能用this
  • 避免多次实例化,优化性能
  • 单一模式
class Person {
  String name;
  // static 静态内容
  static Person instance;
  factory Person([String name = '刘备']) {
    // 工厂构造函数不能使用this
    if (Person.instance == null) {
      // 第一次实例化
      Person.instance = new Person.newSelf(name);
    }
    // 非第一次实例化
    return Person.instance;
  }
  Person.newSelf(this.name); // 使用命名构造函数初始化
}
void main() {
  Person p1 = new Person('关羽'); //工厂函数不能用来实例化
  print(p1.name); //The getter 'name' was called on null

  Person p2 = new Person('张飞');
  print(p2.name);

  print(p1 == p2); // true
}

访问修饰

Dart 与TS不同,没有访问修饰符。

Dart类中,默认修饰符是公开的(即public)

如果属性或方法以 _ 开头,则表示私有(即private)

可以通过getter方法访问

import './lib//Person.dart'; 
void main() {
  // main() 和 Person 在同一作用域,私有则不起作用
  // 只有把类抽离出去,私有才起作用
  print(p._money); // 错 
}

getter与setter

  • Getter (获取器)是通过get关键字修饰的方法

    • 函数没有小括号,访问时也没有小括号(像访问属性-样访问方法)
  • Setter (修改器)是通过set关键字修饰的方法

    • 访问时,像设置属性一样给函数传参
class Circle {
  final double PI = 3.1415;
  num r;
  Circle(this.r);
  // num area() { 普通方法
  //   return (this.PI * this.r * this.r).floor();
  // }
  num get area {
    return (this.PI * this.r * this.r).floor();
  }
   set setR(value) {
    this.r = value;
  }
}

void main() {
  var c = new Circle(10);
  print(c.area); // 使用gatter
  //通过set修改
  c.setR = 20;
}

初始化列表

  • 作用:在构造函数中设置属性的默认值
  • 时机:在构造函数体执行之前执行
  • 语法:使用逗号分隔初始化表达式
  • 场景:常用于设置final常量的值
class Rect {
    int height, width;
    // 当类被初始化时,给属性赋值
    Rect(): height = 1, width = 1 {
        // $访问的时参数。${}访问属性
        print('${this.height}----${this.width}');
    } 
}
class Point {
    double x, y, z;
    // 初始化列表特殊用法 重定向构造函数
    // 把z改成0,x、y时调用twoD()传递来的
    Point.twoD(double x, double y) : this(x, y, 0);
}
void main() {
    var p2 = new Point.twoD(3, 4); // 这里只能传递x y。z已经被改成0了
    print(p2.z); // 0.0
}

static关键字

static关键字用来指定静态成员。通过static修饰的属性是静态属性,通过static修饰的方法是静态方法。

静态成员可以通过类名称直接访问(不需要实例化)

静态方法中不能访问非静态成员,非静态方法可以访问静态成员

静态方法不能使用this关键字

实例化是比较消耗资源的,声明静态成员,可以提高程序性能

class Person {
  static String name = '张三';
  int age = 18;
  static printInfo() {
    // print(this.name); // ❌ 不能使用this访问静态属性
    print(name); // 直接访问静态书信
    // print(this.age); // static方法不能用this 静态方法不能非静态属性
  }

  printUserInfo() {
    print(name); // 非静态方法可以访问静态属性
  }
}

void main(List<String> args) {
  // 静态成员可以通过类名称直接访问
  print(Person.name);
  print(Person.printInfo()); // 返回的是null
  // Psreon. 只能访问静态的
}

元数据

  • 元数据以 @ 开头,可以给代码标记些额外信息 。可以用来库、类、构造器、函数、字段、参数或变量声明
元数据含义
@overrid(重写)谋方法添加该注解,表示重写父类中同名方法
@required(必填)注解dart中的命名参数
@deprecated(弃用)标记类或方法不在建议使用

继承

子类可以使用父类中可见的内容。通过super关键字引用父类可见内容

class Son extends Father{}

抽象类

  • 抽象类是用abstract关键字修饰的类
  • 抽象类的作用是充当普通类的模板,约定一些必要的属性和方法
  • 抽象防范是指没有方法体的方法
    • 普通类不能有抽象方法
    • 抽象类中一般都有抽象方法,也可以没有
  • 抽象类不能被实例化,可以被继承,继承后需要实现所有抽象方法
  • 可以充当接口被实现,普通类必须实现抽象类里定义的所有属性
abstract class Phone {
  void processor(); // 抽象方法
  void camera();
}

class Xiaomi extends Phone {
  @override
  void camera() {
    // TODO: implement camera
    print('骁龙888+');
  }
  void processor() {
    print('普通方法');
  }
}

接口

接口在Dart中就是一个类(只是用法不同)与java不同,java中接口需要用interface关键字声明,Dart不需要。接口可以是任意类,但一般使用抽象类做接口。一个类实现多个接口需要使用逗号分隔。

普通类实现接口后,必须重写接口中的所有属性和方法。

abstract class Processor {}
abstract class Camera {}
class Phone implements Processor, Camera {}

混入(Mixin)

“混入”是一段公共代码。混入有两种声明方式

  1. 将类当作混入class MixinA{}。作为Mixin的类只能继承与Object且不能有构造函数
  2. 使用 mixin 关键字声明

混入可以提高代码复用的效率,普通类课通过with实现混入。class A with MixinA

使用多个混入时,后引入的混入会覆盖之前混入中的重复的内容。

// class MixinA extends Father { 只能继承Object类
class MixinA {
  String name = 'mixinA';
  // MixinA(); // 不能有自己的构造函数
  void printA() {
    print('A');
  }
}
mixin MixinB {
  String name = 'mixinB';
  void printB() {
    print('B');
  }
}

class MyClass with MixinA, MixinB {
  // 可以使用混入进来的类的方法和属性
}

void main() {
  var c = new MyClass();
  c.printA(); // A
  c.printB(); // B
}

泛型

泛型实在函数、类、接口中指定宽泛数据类型的语法。他们分别称为

  • 泛型函数
  • 泛型类
  • 泛型接口
T getData<T>(T value) {
    return value;
}

1、泛型函数

// 泛型函数
T getData<T>(T value) {
  return value;
}

void main() {
  print(getData<String>('10'));
  print(getData<int>(20));
}
Set s = <int>{}; // 泛型set
s.add(1);

2、泛型类


// 泛型类
class GenericsClass<T> {
  Set s = new Set<T>();

  add(T value) {
    this.s.add(value);
  }

  void info() {
    print(this.s);
  }
}

void main() {
  GenericsClass g = new GenericsClass<String>();
  g.add('str'); // {str}
    GenericsClass g = new GenericsClass<int>();
  g.add('10'); // {10}
}

3、泛型接口

// 泛型接口
abstract class Cache<T> {
  getKey(String key);
  void setByKey(String key, T value);
}
// 文件缓存
class FileCache<T> implements Cache<T> {
  @override
  getKey(String key) {
    return null;
  }
  @override
  void setByKey(String key, T value) {
    print('文件缓存:key=${key} value = $value');
  }
}
void main() {
  // 文件缓存
  FileCache fc = new FileCache<String>();
  fc.setByKey('foo', 'bar');
  // fc.setByKey('foo', 2); // 报错,已经传递String泛型
}

泛型限制

class SomeBaseClass {}

// 传入的类型必须是继承了SomeBaseClass
class Foo<T extends SomeBaseClass> {
  String toString() => "Instance of 'Foo<$T>'";
}

class AnotherClass {// ...}
class Extender extends SomeBaseClass {// 子类}

void main() {
  var someBaseClassFoo = Foo<SomeBaseClass>();
  print(someBaseClassFoo); //Instance of 'Foo<SomeBaseClass>'

  var extendeFoo = Foo<Extender>();
  print(extendeFoo); // Instance of 'Foo<Extender>'
  // var f = Foo<AnotherClass>(); // 报错了,Another没有继承SomeBaseClass
}

枚举

枚举是数量固定的常量值,通过enum关键字声明。

final、static声明的变量是分散的。

enum Color { red, green, blue }

void main(List<String> args) {
  print(Color.green.index); // 1 通过index 返回枚举中具体常量的值

  // 通过 values 返回常量列表
  List<Color> colors = Color.values; // [Color.red, Color.green, Color.blue]
  print(colors); // 是一个列表
    
  // 通过下标,访问内容
  print(colors[0]); //Color.red

  colors.forEach((element) => print('value: $element,index: ${element.index}'));
  /**
    value: Color.red,index: 0
    value: Color.green,index: 1
    value: Color.blue,index: 2
  */
}

dart 库与生态

Dart中的库就是具有特定功能的模块,可能包含单个文件,也可能包含多个文件。

按照库的作者进行划分,库可以分成三类

  1. 自定义库(工程师自己写的)

  2. 系统库(Dart 中自带的)

  3. 第三方库(Dart 生态中的)

    pub命令在D:\File\flutter\bin\cache\dart-sdk\bin

@Dart@JavaScript
库(library)包(package)
https://pub.devhttps://npmjs.com
pubspec.yamlpackage.json
pubnpm

自定义库

通过 library来声明库

每个Dart文件默认都是一个库,只是没有使用library声明

Dart使用下划线开头的标识符,表示库内访问可见(私有)

library关键字声明的库名称建议使用:小写字母+下划线

// 自定义库
library MyCustom; // 大驼峰在dart没事,在flutter有问题
library my_custom;
class MyCustom {}
// 引用
import 'lib/MyCustom.dart';

系统库

是Dart提供的常用内置库,直接引入就可以用

import 'dart:math';
import 'dart:core'; // 自动引入的,写不写都行
void main() {
  print(pi); // 3.141592653589793
  print(min(3, 6)); // 3
}

第三方库

来源:

  • https://pub.dev
  • https://pub.flutter-io.cn/packages
  • https://pub.dartlang.org/flutter

使用

  • 在项目目录下创建pubspec.yaml
  • 在pubspec.yaml中声明第三方库(依赖)
  • 命令行进入pubspec所在目录,执行pup get进行安装
  • 项目中引入已安装第三方库 import 'packages:xxx/xxx.dart';

引入部分库

仅引入需要的内容。使用show关键字

// 只引入 f1() f2()方法
import 'lib/Common.dart' show f1, f2;
// 引入时,隐藏了f3()方法
import 'lib/Common.dart' hide f3;

引入冲突

// Common和function里都有f1()
import 'lib/Common.dart';
import 'lib/function.dart' as func;
f1();
func.f1(); // 这样调用

延迟引入-懒加载

// 建立关系
import 'lib/function.dart' deferred as func;

void main() {
  // func.hello();
  print('1');
  greet();
  print('2');
  print('3');
  // 执行顺序: 1 2 3 hello
}

Future greet() async {
  await func.loadLibrary(); // 调用这个方法才会真的加载
  func.hello();
}

part与prt of

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7pl79cCk-1657018032136)(D:\File\learn\Flutter\笔记\images\part.png)]

// 摄像头 Camera.dart
// 与主库建立联系
part of phone;
// 处理器 Processor.dart
// 与主库建立联系 
part of phone;
library phone; 
// 与分库建立联系
part 'Camera.dart';
part 'Processor.dart';
// 测试
import 'lib/phone/main.dart';

void main() {
  Camera c = new Camera();
  c.info(); //  是摄像头哦

  Processor p = new Processor();
  p.info(); //  是处理器哦
}

mon.dart’;
import ‘lib/function.dart’ as func;
f1();
func.f1(); // 这样调用


### 延迟引入-懒加载

~~~dart
// 建立关系
import 'lib/function.dart' deferred as func;

void main() {
  // func.hello();
  print('1');
  greet();
  print('2');
  print('3');
  // 执行顺序: 1 2 3 hello
}

Future greet() async {
  await func.loadLibrary(); // 调用这个方法才会真的加载
  func.hello();
}

part与prt of

请添加图片描述

// 摄像头 Camera.dart
// 与主库建立联系
part of phone;
// 处理器 Processor.dart
// 与主库建立联系 
part of phone;
library phone; 
// 与分库建立联系
part 'Camera.dart';
part 'Processor.dart';
// 测试
import 'lib/phone/main.dart';

void main() {
  Camera c = new Camera();
  c.info(); //  是摄像头哦

  Processor p = new Processor();
  p.info(); //  是处理器哦
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值