01、泛型方法
通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)
//只能返回string类型的数据
String getData(String value){
return value;
}
//同时支持返回 string类型 和int类型 (代码冗余)
String getData1(String value){
return value;
}
int getData2(int value){
return value;
}
//同时返回 string类型 和number类型 不指定类型可以解决这个问题
getData(value){
return value;
}
//不指定类型放弃了类型检查。我们现在想实现的是传入什么 返回什么。比如:传入number 类型必须返回number类型 传入 string类型必须返回string类型
T getData<T>(T value){
return value;
}
getData<T>(T value){
return value;
}
void main(){
// print(getData(21));
// print(getData('xxx'));
// getData<String>('你好');
print(getData<int>(12));
}
02、泛型类
//集合List 泛型类的用法
//案例:把下面类转换成泛型类,要求MyList里面可以增加int类型的数据,也可以增加String类型的数据。但是每次调用增加的类型要统一
/*
class MyList {
List list = <int>[];
void add(int value) {
this.list.add(value);
}
List getList() {
return list;
}
}
MyList l = new MyList();
l.add(1);
l.add(12);
l.add(5);
print(l.getList());
*/
class MyList<T> {
List list = <T>[];
void add(T value) {
this.list.add(value);
}
List getList() {
return list;
}
}
main() {
// MyList l1=new MyList();
// l1.add("张三");
// l1.add(12);
// l1.add(true);
// print(l1.getList());
// MyList l2 = new MyList<String>();
// l2.add("张三1");
// // l2.add(11); //错误的写法
// print(l2.getList());
MyList l3 = new MyList<int>();
l3.add(11);
l3.add(12);
l3.add("aaaa");
print(l3.getList());
// List list = List.filled(2, "");
// list[0] = "张三";
// list[1] = "李四";
// print(list);
// List list = new List.filled(2, "");
// list[0] = "张三1";
// list[1] = "李四";
// print(list);
// List list = new List<String>.filled(2, "");
// list[0] = "张三1";
// list[1] = "李四";
// print(list);
// List list2 = new List<int>.filled(2, 0);
// list2[0] = 12;
// list2[1] = 13;
// print(list2);
}
03、泛型接口
/*
Dart中的泛型接口:
实现数据缓存的功能:有文件缓存、和内存缓存。内存缓存和文件缓存按照接口约束实现。
1、定义一个泛型接口 约束实现它的子类必须有getByKey(key) 和 setByKey(key,value)
2、要求setByKey的时候的value的类型和实例化子类的时候指定的类型一致
*/
// abstract class ObjectCache {
// getByKey(String key);
// void setByKey(String key, Object value);
// }
// abstract class StringCache {
// getByKey(String key);
// void setByKey(String key, String value);
// }
// abstract class Cache<T> {
// getByKey(String key);
// void setByKey(String key, T value);
// }
abstract class Cache<T>{
getByKey(String key);
void setByKey(String key, T value);
}
class FlieCache<T> implements Cache<T>{
@override
getByKey(String key) {
return null;
}
@override
void setByKey(String key, T value) {
print("我是文件缓存 把key=${key} value=${value}的数据写入到了文件中");
}
}
class MemoryCache<T> implements Cache<T>{
@override
getByKey(String key) {
return null;
}
@override
void setByKey(String key, T value) {
print("我是内存缓存 把key=${key} value=${value} -写入到了内存中");
}
}
void main(){
// MemoryCache m=new MemoryCache<String>();
// m.setByKey('index', '首页数据');
MemoryCache m=new MemoryCache<Map>();
m.setByKey('index', {"name":"张三","age":20});
}
04、Dart中的库
前面介绍Dart基础知识的时候基本上都是在一个文件里面编写Dart代码的,但实际开发中不可能这么写,模块化很重要,所以这就需要使用到库的概念。
在Dart中,库的使用时通过import关键字引入的。
library指令可以创建一个库,每个Dart文件都是一个库,即使没有使用library指令来指定。
Dart中的库主要有三种:
1、我们自定义的库
import 'lib/xxx.dart';
2、系统内置库
import 'dart:math';
import 'dart:io';
import 'dart:convert';
3、Pub包管理系统中的库
https://pub.dev/packages
https://pub.flutter-io.cn/packages
https://pub.dartlang.org/flutter/
1、需要在自己想项目根目录新建一个pubspec.yaml
2、在pubspec.yaml文件 然后配置名称 、描述、依赖等信息
3、然后运行 pub get 获取包下载到本地
4、项目中引入库 import 'package:http/http.dart' as http; 看文档使用
05、Dart中的async和await
async和await
这两个关键字的使用只需要记住两点:
只有async方法才能使用await关键字调用方法
如果调用别的async方法必须使用await关键字
async是让方法变成异步。
await是等待异步方法执行完成。
void main() async{
var result = await testAsync();
print(result);
}
//异步方法
testAsync() async{
return 'Hello async';
}
06、导入pub包管理系统和冲突解决
/*
pub包管理系统:
1、从下面网址找到要用的库
https://pub.dev/packages
https://pub.flutter-io.cn/packages
https://pub.dartlang.org/flutter/
2、创建一个pubspec.yaml文件,内容如下
name: xxx
description: A new flutter module project.
dependencies:
http: ^0.12.0+2
date_format: ^1.0.6
3、配置dependencies
4、运行pub get 获取远程库
5、看文档引入库使用
*/
import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
import 'package:date_format/date_format.dart';
main() async {
// var url = "http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1";
// // Await the http get response, then decode the json-formatted responce.
// var response = await http.get(url);
// if (response.statusCode == 200) {
// var jsonResponse = convert.jsonDecode(response.body);
// print(jsonResponse);
// } else {
// print("Request failed with status: ${response.statusCode}.");
// }
print(formatDate(DateTime(1989, 2, 21), [yyyy, '*', mm, '*', dd]));
}
1、冲突解决
当引入两个库中有相同名称标识符的时候,如果是java通常我们通过写上完整的包名路径来指定使用的具体标识符,甚至不用import都可以,但是Dart里面是必须import的。当冲突的时候,可以使用as关键字来指定库的前缀。如下例子所示:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
Element element1 = new Element(); // Uses Element from lib1.
lib2.Element element2 = new lib2.Element(); // Uses Element from lib2.
import 'lib/Person1.dart';
import 'lib/Person2.dart' as lib;
main(List<String> args) {
Person p1=new Person('张三', 20);
p1.printInfo();
lib.Person p2=new lib.Person('李四', 20);
p2.printInfo();
}
07、部分导入和延迟加载
部分导入
如果只需要导入库的一部分,有两种模式:
模式一:只导入需要的部分,使用show关键字,如下例子所示:
import 'package:lib1/lib1.dart' show foo;
模式二:隐藏不需要的部分,使用hide关键字,如下例子所示:
import 'package:lib2/lib2.dart' hide foo;
// import 'lib/myMath.dart' show getAge;
import 'lib/myMath.dart' hide getName;
void main(){
// getName();
getAge();
}
延迟加载
也称为懒加载,可以在需要的时候再进行加载。
懒加载的最大好处是可以减少APP的启动时间。
懒加载使用deferred as关键字来指定,如下例子所示:
import 'package:deferred/hello.dart' deferred as hello;
当需要使用的时候,需要使用loadLibrary()方法来加载:
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
08、Dart 新特性
/*
Null safety翻译成中文的意思是空安全。
null safety 可以帮助开发者避免一些日常开发中很难被发现的错误,并且额外的好处是可以改善性能。
Flutter2.2.0(2021年5月19日发布) 之后的版本都要求使用null safety。
? 可空类型
! 类型断言
*/
String? getData(apiUrl){
if(apiUrl!=null){
return "this is server data";
}
return null;
}
// void printLength(String? str){
// // print(str!.length);
// if (str!=null){
// print(str.length);
// }
// }
void printLength(String? str){
try {
print(str!.length);
} catch (e) {
print("str is null");
}
}
void main(args) {
//1、 ? 可空类型
// int a=123;
// print(a);
// String username="张三";
// print(username);
// List<String> l1=["张三","李四","王五"];
// print(l1);
// int a=123; //非空的int类型
// a=null; //A value of type 'Null' can't be assigned to a variable of type 'int'
// String username="张三"; //非空的String类型
// username=null; //A value of type 'Null' can't be assigned to a variable of type 'String'.
// String? username="张三"; // String? 表示username是一个可空类型
// username=null;
// print(username);
// int? a=123; // int? 表示a是一个可空类型
// a=null;
// print(a);
// List<String> l1=["张三","李四","王五"];
// l1=null; //A value of type 'Null' can't be assigned to a variable of type 'List<String>'.
// List<String>? l1=["张三","李四","王五"];
// l1=null;
// print(l1);
//调用方法
// print(getData("http://www.itying.com"));
// print(getData(null));
// ! 类型断言
// String? str="this is str";
// str=null;
// print(str!.length);
//类型断言: 如果str不等于null 会打印str的长度,如果等于null会抛出异常
// printLength("str");
printLength(null);
}
/*
Null safety翻译成中文的意思是空安全。
late 关键字主要用于延迟初始化。
*/
class Person {
late String name;
late int age;
void setName(String name, int age) {
this.name = name;
this.age = age;
}
String getName() {
return "${this.name}---${this.age}";
}
}
void main(args) {
Person p = new Person();
p.setName("张三", 20);
print(p.getName());
}
/*
Null safety翻译成中文的意思是空安全。
required翻译成中文的意思是需要、依赖
required关键词:
最开始 @required 是注解
现在它已经作为内置修饰符。
主要用于允许根据需要标记任何命名参数(函数或类),使得它们不为空。因为可选参数中必须有个 required 参数或者该参数有个默认值。
*/
String printUserInfo(String username, {int age=10, String sex="男"}) {//行参
return "姓名:$username---性别:$sex--年龄:$age";
}
String printInfo(String username, {required int age, required String sex}) {//行参
return "姓名:$username---性别:$sex--年龄:$age";
}
// name 可以传入也可以不传入 age必须传入
class Person {
String? name; //可空属性
int age;
Person({this.name,required this.age}); //表示 name 和age 必须传入
String getName() {
return "${this.name}---${this.age}";
}
}
void main(args) {
print(printUserInfo('张三'));
print(printUserInfo('张三',age: 20,sex: "女"));
//age 和 sex必须传入
print(printInfo('张三',age: 22,sex: "女"));
}