简介
Dart
是由谷歌开发的计算机编程语言,它可以被用于web
、服务器、移动应用 和物联网等领域的开发。Dart
诞生于2011
年,号称要取代JavaScript
。但是过去的几年中一直不温不火。直到Flutter
的出现现在被人们重新重视。- 要学
Flutter
的话我们必须首先得会Dart
。 - 官网:https://dart.cn/
基本
- 跟
C
语言一样,入口方法是main()
方法
main() {
print('hello');
}
// 表示main方法没有返回值
// void main(){
// print('hello');
// }
- 语句后面需要带
;
重要的概念
在学习 Dart
语言时, 应该基于以下事实和概念:
-
任何保存在变量中的都是一个对象, 并且所有的对象都是对应一个类的实例。 无论是数字,函数和
null
都是对象。所有对象继承自Object
类。 -
尽管
Dart
是强类型的,但是Dart
可以推断类型,所以类型注释是可选的。 如果要明确说明不需要任何类型, 需要使用特殊类型dynamic
。 -
Dart
支持泛型,如List <int>
(整数列表)或List <dynamic>
(任何类型的对象列表)。 -
Dart
支持顶级函数(例如main()
), 同样函数绑定在类或对象上(分别是 静态函数 和 实例函数 )。 以及支持函数内创建函数 ( 嵌套 或 局部函数 ) 。 -
类似地,
Dart
支持顶级 变量 , 同样变量绑定在类或对象上(静态变量和实例变量)。 实例变量有时称为字段或属性。 -
与
Java
不同,Dart
没有关键字“public”
,“protected”
和“private”
。 如果标识符以下划线(_
)开头,则它相对于库是私有的。 -
标识符 以字母或下划线(
_
)开头,后跟任意字母和数字组合。
Dart
工具提示两种类型问题:警告_和_错误。 警告只是表明代码可能无法正常工作,但不会阻止程序的执行。 错误可能是编译时错误或者运行时错误。 编译时错误会阻止代码的执行; 运行时错误会导致代码在执行过程中引发异常。
变量
dart
是可以不预先定义变量类型 ,自动会类型推导dart
中定义变量可以通过var
关键字可以通过类型来申明变量- 如果要明确说明不需要任何类型, 需要使用特殊类型
dynamic
var str = 'this is var';
String str = 'this is var';
int str = 123;
备注:
var
后就不要写类型,写了类型不要var
。比如var int a = 5;
会报错- 未初始化时,变量默认值是
null
常量
- 使用
final
或者const
修饰符 const
:值不变 一开始就得赋值final
:可以开始不赋值 只能赋一次final
不仅有const
的编译时常量的特性,最重要的它是运行时常量,并且final
是惰性初始化,即在运行时第一次使用前才初始化
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere
命令规则
- 变量名称必须由数字、字母、下划线和美元符(
$
)组成。 - 标识符开头不能是数字
- 标识符不能是保留字和关键字。
- 变量的名字是区分大小写的如:
age
和Age
是不同的变量。在实际的运用中也建议,不要用一个单词大小写区分两个变量。 - 标识符(变量名称)一定要见名知意:变量名称建议用名词,方法名称建议用动词
数据类型
数值 - int、double
int
比如是整型。整数值不大于64位,具体取决于平台double
既可以是整型,也可以是浮点型。64位(双精度)浮点数- 运算符
+
、-
、*
、/
、%
int a = 123;
double b = 23.5;
b = 24;
var c = a + b;
print(c);
// 字符串 和 数字 互转
// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
操作方法的库:dart:math
库
字符串 - String
- 使用单引号
'
或者双引号"
都可以 - 多行使用三个单引号
'
或者三个双引号"
包裹起来 - 字符串中变量使用
${str}
var str1 = 'this is str1';
String str2 = 'this is str2';
// 连续三个单引号或者三个双引号实现多行字符串对象的创建
String str3 = '''
str3
str3
''';
// 通过 ${expression} 的方式内嵌表达式。 如果表达式是一个标识符,则 {} 可以省略
print("$str1 $str2");
// 使用 + 运算符来把多个字符串连接为一个
print(str1 + " " + str2);
// 使用 r 前缀,可以创建 “原始 raw” 字符串
var s = r"In a raw string, even \n isn't special.";
布尔值 - bool
- 值为
true
或者false
// 检查空字符串。
var fullName = '';
assert(fullName.isEmpty);
// 检查 0 值。
var hitPoints = 0;
assert(hitPoints <= 0);
// 检查 null 值。
var unicorn;
assert(unicorn == null);
// 检查 NaN 。
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
数组 - List
- 在
Dart
中,数组是列表对象,所以大多数人只是称它们为列表
// 会自动类型推断成 List<string>
var list1 = ['aaa', 'bbb', 'ccc'];
print(list1.length);
print(list1[1])
var list2 = new List();
list2.add('张三');
// 指定列表中的每项是String类型
var list3 = new List<String>();
list3.add('张三');
List
常用的属性和方法
length
:长度reversed
:翻转isEmpty
:是否为空isNotEmpty
:是否不为空add()
:增加addAll()
:拼接数组indexOf()
:查找传入具体值remove()
:删除传入具体值removeAt()
:删除传入索引值fillRange()
:修改insert(index,value)
:指定位置插入insertAll(index,list)
:指定位置插入List
toList()
:其他类型转换成List
join()
:List
转换成字符串split()
:字符串转化成List
forEach()
:遍历map()
:遍历where()
:遍历any()
:遍历every()
:遍历
// 循环打印出每个项
List myList = ['香蕉','苹果','西瓜'];
// for循环
for(var i = 0; i < myList.length; i++) {
print(myList[i]);
}
// for in
for(var item in myList){
print(item);
}
// forEach
myList.forEach((value){
print("$value");
});
// 每项*2 生成一个新List
List myList = [1, 3, 4];
// for 循环
List newList = new List();
for(var i = 0; i < myList.length; i++) {
newList.add(myList[i] * 2);
}
// map
var newList = myList.map((value) {
return value*2;
});
// 按条件查找
List myList = [1, 3, 4, 5, 7, 8, 9];
// where
var newList = myList.where((value){
return value > 5;
});
print(newList.toList());
// any 只要集合里面有满足条件的就返回true
var f = myList.any((value){
return value>5;
});
// every 每一个都满足条件返回true 否则返回false
var f = myList.every((value) {
return value > 5;
});
Set
Set
最主要的功能就是去除数组重复内容Set
是没有顺序且不能重复的集合,所以不能通过索引去获取值
var s1 = new Set();
s1.add('香蕉');
s1.add('苹果');
s1.add('苹果');
print(s1); // {香蕉, 苹果}
print(s1.toList());
// 去除List中重复项
List myList=['香蕉','苹果','西瓜','香蕉','苹果','香蕉','苹果'];
var s2 = new Set();
s2.addAll(myList);
print(s2);
print(s2.toList());
// forEach
var s = new Set();
s.addAll([1, 222, 333]);
s.forEach((value) => print(value));
// map
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
字典 - Map
- 通常来说,
Map
是一个键值对相关的对象。键和值可以是任何类型的对象。每个键只出现一次,而一个值则可以出现多次
var person = {
"name": "张三",
"age": 20,
"work": ["程序员", "外卖员"]
};
print(person);
print(person['name'])
var p = new Map();
p["name"] = "李四";
Map
常用的属性和方法
keys
:获取所有的key
值values
:获取所有的value
值isEmpty
:是否为空isNotEmpty
:是否不为空remove(key)
:删除指定key
的数据addAll({...})
:合并映射 给映射内增加属性containsValue()
:查看映射内的值,返回true/false
forEach()
:遍历map()
:遍历where()
:遍历any()
:遍历every()
:遍历
Map person = {
"name": "张三",
"age": 20,
"sex": "男"
};
print(person.keys.toList());
print(person.values.toList());
print(person.isEmpty);
print(person.isNotEmpty);
// forEach
person.forEach((key,value) {
print("$key---$value");
});
Runes
Runes
是UTF-32
编码的字符串。它可以通过文字转换成符号表情或者代表特定的文字。
main() {
var clapping = '\u{1f44f}';
print(clapping);
print(clapping.codeUnits);
print(clapping.runes.toList());
Runes input = new Runes('\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(new String.fromCharCodes(input));
}
类型判断
- 使用
is
关键字来判断类型
var str = '1234';
if (str is String) {
print('string类型');
} else if (str is int) {
print('int类型');
} else {
print('其他类型');
}
类型转换
Number
类型转换成String
类型使用toString()
String
类型转成Number
类型使用int.parse()
、double.parse()
// String str = '123';
// var myNum = int.parse(str);
// String str = '123.1';
// var myNum = double.parse(str);
// 防止程序报错,可以用 try catch
String price = '';
try {
var myNum = double.parse(price);
print(myNum);
} catch(err) {
print(0);
}
var count = 12;
var strCount = count.toString();
- 其他类型转换成
Boolean
类型
// isEmpty: 判断字符串是否为空
var str = '';
print(str.isEmpty);
// 数字非0
var myNum = 123;
print(myNum==0);
// 非空
var count;
print(count==null);
// isNaN
var myNum2 = 0 / 0;
print(myNum2.isNaN);
运算符
类型判定运算符
as
, is
, 和 is!
运算符用于在运行时处理类型检查:
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
赋值运算符
使用 =
为变量赋值。 使用 ??=
运算符时,只有当被赋值的变量为 null
时才会赋值给它。
// 将值赋值给变量a
a = value;
// 如果b为空时,将变量赋值给b,否则,b的值保持不变。
// 以下相当于: b = b == null ? value : b
b ??= value;
条件表达式
expr1 ?? expr2
:如果 expr1
不是null
, 返回 expr1
的值; 否则, 执行并返回 expr2
的值。
// 以下相当于: a == null ? b : a
a ?? b
// 如果赋值是根据布尔值, 考虑使用 ?:
var visibility = isPublic ? 'public' : 'private';
// 如果赋值是基于判定是否为 null, 考虑使用 ??
String playerName(String name) => name ?? 'Guest';
级联运算符
级联运算符 (..
) 可以实现对同一个对像进行一系列的操作。
除了调用函数, 还可以访问同一对象上的字段属性。
这通常可以节省创建临时变量的步骤, 同时编写出更流畅的代码。
querySelector('#confirm') // 获取对象。
..text = 'Confirm' // 调用成员变量。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
// 等价于
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
函数
- 形参需要带类型
- 可选参数使用
[]
- 默认参数
=
- 命名参数使用
{}
- 跟
javascript
语法一样,有箭头函数、匿名函数和闭包
String printUserInfo(String username, int age) { // 行参
return "姓名:$username---年龄:$age";
}
print(printUserInfo('张三', 20)); // 实参
// 可选参数
String printUserInfo(String username, [int age]){ //行参
if (age! = null) {
return "姓名:$username---年龄:$age";
}
return "姓名:$username---年龄保密";
}
// 默认参数。如果没有提供默认值,则默认值为 null
String printUserInfo(String username, [String sex='男', int age]){ //行参
if (age! = null) {
return "姓名:$username---年龄:$age";
}
return "姓名:$username---年龄保密";
}
print(printUserInfo('张三'));
print(printUserInfo('小李', '女'));
print(printUserInfo('小李', '女', 30));
// 命名参数
// 调用函数时,可以使用指定命名参数 paramName: value
String printUserInfo(String username, {int age, String sex = '男'}) {
if(age != null) {
return "姓名:$username---性别:$sex--年龄:$age";
}
return "姓名:$username---性别:$sex--年龄保密";
}
print(printUserInfo('张三', age:20, sex:'未知'));
// 使用 @required 注释表示参数是 required 性质的命名参数
const Scrollbar({ Key key, @required Widget child })
// 普通函数 vs 箭头函数
List list = [4, 1, 2, 3, 4];
var newList = list.map((value) {
if (value > 2) {
return value * 2;
}
return value;
});
print(newList.toList());
// 箭头函数
var newList = list.map((value) => value>2 ? value * 2 : value);
print(newList.toList());
- 测试函数是否相等
void foo() {} // 顶级函数
class A {
static void bar() {} // 静态方法
void baz() {} // 示例方法
}
void main() {
var x;
// 比较顶级函数。
x = foo;
assert(foo == x);
// 比较静态方法。
x = A.bar;
assert(A.bar == x);
// 比较实例方法。
var v = A(); // A的1号实例
var w = A(); // A的2号实例
var y = w;
x = w.baz;
// 两个闭包引用的同一实例(2号),
// 所以它们相等。
assert(y.baz == x);
// 两个闭包引用的非同一个实例,
// 所以它们不相等。
assert(v.baz != w.baz);
}
类 - Class
- 类可以直接放在一个
dart
文件中,在另一个文件中通过import
引入使用
import 'lib/Person.dart';
Person p1 = new Person.setInfo('李四', 30);
p1.printInfo();
dart
中没有public
、private
、protected
这些访问修饰符。可以使用_
把一个属性或者方法定义成私有
构造函数
- 默认构造函数名称和类名相同
class Person{
String name;
int age;
// 默认构造函数
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 默认构造函数的简写
// Person(this.name, this.age);
void printInfo(){
print("${this.name}----${this.age}");
}
}
Person p1 = new Person('张三', 20);
- 构造函数可以写多个
class Person{
String name;
int age;
// 默认构造函数的简写
Person(this.name, this.age);
Person.now() {
print('我是命名构造函数');
}
Person.setInfo(String name, int age){
this.name = name;
this.age = age;
}
void printInfo(){
print("${this.name}----${this.age}");
}
}
// 默认实例化类的时候调用的是 默认构造函数
Person p1 = new Person('张三', 20);
// 命名构造函数
Person p2 = new Person.now();
Person p3 = new Person.setInfo('李四',30);
- 工厂构造函数:当执行构造函数并不总是创建这个类的一个新实例时,则使用
factory
关键字
class Logger {
final String name;
bool mute = false;
// 从命名的 _ 可以知,
// _cache 是私有属性。
static final Map<String, Logger> _cache = <String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
getter && setter
- 使用
get
和set
关键字定义 - 调用的时候直接通过访问属性的方式访问
class Rect{
num height;
num width;
Rect(this.height, this.width);
get area {
return this.height * this.width;
}
set areaHeight(value) {
this.height = value;
}
}
Rect r = new Rect(10, 4);
// 调用直接通过访问属性的方式访问area
print("面积:${r.area}");
r.areaHeight = 6;
print(r.area);
静态成员
- 使用
static
关键字来实现类级别的变量和函数 - 静态方法不能访问非静态成员,非静态方法可以访问静态成员
class Person {
static String name = '张三';
int age = 20;
static void show() {
print(name);
}
// 非静态方法可以访问静态成员以及非静态成员
void printInfo(){
// 访问静态属性
print(name);
// 访问非静态属性
print(this.age);
// 调用静态方法
show();
}
// 静态方法
static void printUserInfo(){
// 访问静态属性
print(name);
// 调用静态方法
show();
// 静态方法没法访问非静态的属性
// print(this.age);
// 静态方法没法调用非静态的方法
// this.printInfo();
}
}
print(Person.name);
Person.show();
Person p = new Person();
p.printInfo();
Person.printUserInfo();
对象操作符
?
:条件运算符as
:类型转换is
:类型判断..
:级联操作
class Person {
String name;
num age;
Person(this.name, this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
}
// ?
Person p;
p?.printInfo();
Person p = new Person('张三', 20);
p?.printInfo();
// foo?.bar 非空调用 相当于: foo == null ? null : foo.bar
// 从表达式foo中选择属性bar,
// 除非foo为空(在这种情况下,foo?.bar值为空)
// is
Person p = new Person('张三', 20);
if(p is Person){
p.name = "李四";
}
p.printInfo();
print(p is Object);
// as
var p1;
p1 = '';
p1 = new Person('张三1', 20);
// p1.printInfo();
(p1 as Person).printInfo();
// ..
Person p1 = new Person('张三1', 20);
p1.printInfo();
p1..name = "李四"
..age = 30
..printInfo();
类的继承
- 子类使用
extends
关键词来继承父类 - 子类会继承父类里面可见的属性和方法 但是不会继承构造函数
- 子类能复写父类的方法
getter
和setter
- 使用
super
给父类构造函数传参 - 使用
@override
覆盖父类的方法 - 在子类里面使用
super
调用父类的方法
class Person {
String name;
num age;
Person(this.name, this.age);
void printInfo() {
print("${this.name}---${this.age}");
}
work() {
print("${this.name}在工作...");
}
}
class Web extends Person{
String sex;
// 子类跟父类一样的参数(没有sex),可以去掉后面的{}
// Web(String name, num age) : super(name, age);
Web(String name, num age, String sex) : super(name, age){
this.sex = sex;
}
run(){
print('run');
// 调用父类的方法
super.work();
}
// 覆写父类的方法。可以写也可以不写 建议在覆写父类方法的时候加上 @override
@override
void printInfo(){
print("姓名:${this.name}---年龄:${this.age}");
}
}
抽象类
-
Dart
抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口 -
抽象类通过
abstract
关键字来定义 -
Dart
中的抽象方法不能用abstract
声明,Dart
中没有方法体的方法我们称为抽象方法。 -
如果子类继承抽象类必须得实现里面的抽象方法
-
如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。
-
抽象类不能被实例化,只有继承它的子类可以
extends
抽象类和implements
的区别:
- 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用
extends
继承抽象类- 如果只是把抽象类当做标准的话我们就用
implements
实现抽象类
// 定义一个Animal 类要求它的子类必须包含eat方法
abstract class Animal{
eat(); // 抽象方法
run(); // 抽象方法
printInfo(){
print('我是一个抽象类里面的普通方法');
}
}
class Dog extends Animal{
@override
eat() {
print('小狗在吃骨头');
}
@override
run() {
// TODO: implement run
print('小狗在跑');
}
}
class Cat extends Animal{
@override
eat() {
// TODO: implement eat
print('小猫在吃老鼠');
}
@override
run() {
// TODO: implement run
print('小猫在跑');
}
}
// 下面这种写法是错误的,抽象类没法直接被实例化
// Animal a=new Animal();
多态
-
允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果
-
子类的实例赋值给父类的引用
-
多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现
abstract class Animal{
eat(); // 抽象方法
}
class Dog extends Animal{
@override
eat() {
print('小狗在吃骨头');
}
run(){
print('run');
}
}
class Cat extends Animal{
@override
eat() {
print('小猫在吃老鼠');
}
run(){
print('run');
}
}
接口
-
dart
的接口没有interface
关键字定义接口,而是普通类或抽象类都可以作为接口被实现 -
使用
implements
关键字进行实现 -
如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍
-
而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像
Java
接口那样的方式,一般会使用抽象类 -
建议使用抽象类定义接口
接口实现
// 定义一个DB库 支持 mysql mssql mongodb
// mysql mssql mongodb三个类里面都有同样的方法
abstract class Db{ // 当做接口 接口:就是约定 、规范
String uri; // 数据库的链接地址
add(String data);
save();
delete();
}
class Mysql implements Db{
@override
String uri;
Mysql(this.uri);
@override
add(data) {
// TODO: implement add
print('这是mysql的add方法'+data);
}
@override
delete() {
// TODO: implement delete
return null;
}
@override
save() {
// TODO: implement save
return null;
}
remove(){
}
}
class MsSql implements Db{
@override
String uri;
@override
add(String data) {
print('这是mssql的add方法'+data);
}
@override
delete() {
// TODO: implement delete
return null;
}
@override
save() {
// TODO: implement save
return null;
}
}
class MongoDb implements Db{
@override
String uri;
@override
add(String data) {
print('这是MongoDb的add方法'+data);
}
@override
delete() {
// TODO: implement delete
return null;
}
@override
save() {
// TODO: implement save
return null;
}
}
代码分离
可以将代码分离到不同的文件中,实现代码分离。
- 新建
Db.dart
文件
abstract class Db{ // 当做接口 接口:就是约定 、规范
String uri; // 数据库的链接地址
add(String data);
save();
delete();
}
- 新建
MySql.dart
文件
import 'Db.dart';
class Mysql implements Db{
@override
String uri;
Mysql(this.uri);
@override
add(data) {
print('这是mysql的add方法'+data);
}
@override
delete() {
return null;
}
@override
save() {
return null;
}
}
- 新建
MsSql.dart
、MongDb.dart
文件
多个接口
abstract class A{
String name;
printA();
}
abstract class B{
printB();
}
class C implements A,B{
@override
String name;
@override
printA() {
print('printA');
}
@override
printB() {
// TODO: implement printB
return null;
}
}
mixins
-
mixins
的中文意思是混入,就是在类中混入其他功能。 -
在
Dart
中可以使用mixins
实现类似多继承的功能 -
使用
with
关键字实现
- 作为
mixins
的类只能继承自Object
,不能继承其他类- 作为
mixins
的类不能有构造函数- 一个类可以
mixins
多个mixins
类mixins
绝不是继承,也不是接口,而是一种全新的特性
// 简单混入
class A {
String info = "this is A";
void printA(){
print("A");
}
}
class B {
void printB() {
print("B");
}
}
class C with A, B{
}
// 继承+混入
class Person{
String name;
num age;
Person(this.name, this.age);
printInfo() {
print('${this.name}----${this.age}');
}
void run() {
print("Person Run");
}
}
class A {
String info = "this is A";
void printA() {
print("A");
}
void run() {
print("A Run");
}
}
class B {
void printB() {
print("B");
}
void run() {
print("B Run");
}
}
class C extends Person with B,A{
C(String name, num age) : super(name, age);
}
泛型
- 通俗理解:泛型就是解决类、接口、方法的复用性、以及对不特定数据类型的支持(类型校验)
//只能返回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;
}
print(getData(21));
print(getData('xxx'));
getData<String>('你好');
print(getData<int>(12));
// 集合List泛型类的用法
// 把下面类转换成泛型类,要求List里面可以增加int类型的数据,也可以增加String类型的数据。但是每次调用增加的类型要统一
List list = new List<String>();
// list.add(12); // 错误的写法
list.add('你好');
class PrintClass<T> {
List list = new List<T>();
void add(T value){
this.list.add(value);
}
void printInfo() {
for(var i = 0; i < this.list.length; i++) {
print(this.list[i]);
}
}
}
PrintClass p1 = new PrintClass<String>();
p1.add('你好');
p1.add('哈哈');
p1.printInfo();
PrintClass p2 = new PrintClass<int>();
p2.add(12);
p2.add(23);
p2.printInfo();
// Dart中的泛型接口:
// 实现数据缓存的功能:有文件缓存、和内存缓存。内存缓存和文件缓存按照接口约束实现。
// 1、定义一个泛型接口 约束实现它的子类必须有getByKey(key) 和 setByKey(key,value)
// 2、要求setByKey的时候的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} -写入到了内存中");
}
}
MemoryCache m1 = new MemoryCache<String>();
m1.setByKey('index', '首页数据');
MemoryCache m2 = new MemoryCache<Map>();
m2.setByKey('index', {"name":"张三","age":20});
库
-
实际开发中,模块化很重要,所以这就需要使用到库的概念
-
在
Dart
中,库的使用时通过import
关键字引入的 -
library
指令可以创建一个库,每个Dart
文件都是一个库,即使没有使用library
指令来指定。 -
当引入两个库中有相同名称标识符的时候,可以使用as关键字来指定库的前缀
import 'lib/Person1.dart';
import 'lib/Person2.dart' as lib;
- 部分导入:可以使用
show
关键字只导入需要的部分;或者使用hide
关键字隐藏不需要的部分
import 'package:lib1/lib1.dart' show foo;
import 'package:lib2/lib2.dart' hide foo;
- 延迟加载使用
deferred as
关键字来指定。当需要使用的时候,需要使用loadLibrary()
方法来加载
import 'package:deferred/hello.dart' deferred as hello;
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
自定义的库
- 导入方式:
import 'lib/xxx.dart';
系统内置库
- 导入方式如下
import 'dart:math';
import 'dart:io';
import 'dart:convert';
// 导入系统内置库实现请求数据httpClient
import 'dart:io';
import 'dart:convert';
void main() async{
var result = await getDataFromZhihuAPI();
print(result);
}
// api接口: http://news-at.zhihu.com/api/3/stories/latest
getDataFromZhihuAPI() async{
// 1、创建HttpClient对象
var httpClient = new HttpClient();
// 2、创建Uri对象
var uri = new Uri.http('news-at.zhihu.com', '/api/3/stories/latest');
// 3、发起请求,等待请求
var request = await httpClient.getUrl(uri);
//4、关闭请求,等待响应
var response = await request.close();
//5、解码响应的内容
return await response.transform(utf8.decoder).join();
}
Pub包管理系统中的库
- 从下面网址找到要用的库
- 创建一个
pubspec.yaml
文件,内容如下
name: xxx
description: A new flutter module project.
dependencies:
http: ^0.12.0+2
date_format: ^1.0.6
-
配置
pubspec.yaml
文件中的dependencies
-
运行
pub get
获取远程库 -
看文档引入库使用
import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
import 'package:date_format/date_format.dart';
print(formatDate(DateTime(1989, 2, 21), [yyyy, '*', mm, '*', dd]));
发表评论