01-Hello World
- dart语言的入口函数是main()函数,并且必须显示定义;该函数没有返回值。
- 传递给main的命令行参数是通过List(可选参数)。
- 每行语句必须用分号结尾。
02-定义变量
明确声明
类型推导
- var使用
var name = 'dsfjh'
name = 18
- dynamic使用(可以存储任何类型)
1.在开发中,不建议使用dynamic类型变量会带来风险
dynamic name = 'ddf';
name = 19
2.Object也可以定义变量,与dynamic的区别是:
Object调用方法时,编译时会报错;(由于Object声明的对象是Object类型,所以只能使用Object类的变量和方法,不能使用其当前字类的方法,比如String.length等)
dynamic调用方法时编译不报错,但是运行时会存在安全隐患。(可能由于类型不一样导致错误调用)
- final和const使用
相同点:都是定义常量,不可改变。
不同点:const赋值,在编译期间就已经确定;
final赋值可以动态获取,比如赋值一个函数。(一旦赋值就会有确定的结果,不会再次赋值)
案例demo:
class Person{
const Person();
}
main(List<String> args) {
final a = const Person();
final b = const Person();
print(identical(a, b));
final m = Person();
final n = Person();
print(identical(m, n));
}
03-数据类型
数字类型
1.整数用int,浮点数用double。
2.int和double可表示的范围取决于运行dart的平台。
3.字符串转数字:int/double.parse('123')
数字转字符串:123.toString()/toStringAsFixed
布尔类型
var str = 'fff'
if(str){
print('str')
}
字符串类型
1.单引号和双引号皆可。
2.可以用3个单引号或者双引号表示多行字符串
var str = '''djf
jopdfop
siufoidsf'''
3.字符串与其他变量或者表达式拼接:${} ,如果表达式是一个标识符,{}可以省略
'my name is ${name}, age is $age'
集合类型
- 定义
- List(元素有序,且不一定不重复)
1.使用类型推导定义
var list = ['a','s','d']
2.明确指明类型
List<int> list = [1,5,3]
- Set(元素无序,且不重复)---可用于去重
1.使用类型推导定义
var set = {'s','d'}
2.明确指明类型
Set<int> = {4,5,2}
- Map
1.使用类型推导定义
var map = {'heghf':1.66, 'sddfdff':'dddd'}
2.明确指明类型
Map<String,Object> map = {'heghf':1.66, 'sddfdff':'dddd'}
- 常见操作
- 获取长度属性 length
list.length
set.length
map.length
- 添加/删除/包含操作
list.add(5);
list.remove(1);
list.contains(2);
list.removeAt(2);
- 有关Map操作
1.根据key获取value map['heghf']
2.获取所有的entries map.entries
3.获取所有的keys map.keys
4.获取所有的values map.values
5.判断是否包含某个key或者value map.containsKey('heghf')
6.根据key删除元素 map.remove('heghf')
04-函数
定义
参数问题
函数是一等公民
可以将函数赋值给一个变量,也可以把函数作为另外一个函数的参数或者返回值
匿名函数的使用
main(List<String> args) {
var movies = ['盗梦空间', '星际穿越', '少年派', '大话西游'];
printElement(item) {
print(item);
}
movies.forEach(printElement);
movies.forEach((item) {
print(item);
});
movies.forEach((item) => print(item));
}
词法作用域
根据代码的结构({})来决定作用域范围,优先使用自己作用域的变量,没有再一层层向外寻找。
词法闭包
闭包可以访问其词法范围内的变量,即使函数在其他地方被使用,也可以正常的访问。
返回值问题
所有函数都返回一个值;如果没有返回值,则返回null。(其对应的类型是dynamic类型)
05-运算符
除法、整除、取模运算
??= 赋值操作
当变量有值使用自己原来的值,当变量为null使用后面内容赋值。
main(List<String> args) {
var name2 = null;
name2 ??= 'james';
print(name2);
}
ex1??ex2 条件运算符
//针对于赋值给别的变量
如果ex1是null,则返回ex2的结果
// var temp = 'why'
var temp = null
var name = temp ?? 'kobe'
print(name)
级联语法
对一个对象进行连续的操作
class Person {
String name
void run() {
print("${name} is running")
}
}
main(List<String> args) {
final p1 = Person()
// p1.name = 'why'
// p1.run()
final p2 = Person()
..name = "why"
..run()
}
06-流程控制
if和else
不支持非空即真或者非0即真,必须有明确的bool类型
循环操作
switch-case
每一个case语句,默认情况下必须以一个break结尾。
main(List<String> args) {
var direction = 'east';
switch (direction) {
case 'east':
print('东面');
break;
case 'south':
print('南面');
break;
default:
print('其他方向');
}
}
07-类和对象
类的定义
class 类名 {
类型 成员名;
返回值类型 方法名(参数列表) {
方法体
}
}
举例:创建一个对象(new 关键字可以省略)
main(List<String> args) {
var p = new Person();
p.name = 'why';
p.eat();
}
class Person {
String name;
eat() {
print('$name在吃东西');
}
}
构造方法(构造方法不能有返回值,但是工厂构造方法可以有返回值)
- 普通构造方法
当类中没有明确指定构造方法时,将默认拥有一个无参的构造方法(上述demo就是默认构造方法);
也可以根据自己需求定义构造方法,此时默认的构造方法会失效。(且dart不支持函数重载)
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
Person(this.name, this.age)
}
- 命名构造方法
应用场景:实际开发中希望实现更多的构造方法不能创建相同名称的构造方法,即使用命名构造方法。
class Person {
String name;
int age;
Person() {
name = '';
age = 0;
}
Person.withArgments(String name, int age) {
this.name = name;
this.age = age;
}
@override
String toString() {
return 'name=$name age=$age';
}
}
var p1 = new Person();
print(p1);
var p2 = new Person.withArgments('why', 18);
print(p2);
- 初始化列表
1.常用于设置final变量的值;
2.在构造方法体执行之前执行。
class Person{
final String name;
final int age;
Person(this.name): this.age = age ?? 10 {
}
}
- 重定向构造方法(在一个构造方法中调用另外一个构造方法:是在冒号后面使用this调用)
class Person {
String name;
int age;
Person(this.name, this.age);
Person.fromName(String name) : this(name, 0);
}
- 常量构造方法(传入相同值,返回同一个对象) //一般只写一个常量构造函数
1.默认情况下,创建对象时传入相同的参数创建出来的不是同一个对象;在构造方法前加 const 修饰,可以实现。
main(List<String> args) {
var p1 = const Person('why');
var p2 = const Person('why');
print(identical(p1, p2));
}
class Person {
final String name;
const Person(this.name);
}
2.注意
** 拥有常量构造方法的类中,所有的成员变量必须是 final 修饰的.
** 为了可以通过常量构造方法,创建出相同的对象,不再使用new关键字,而是使用 const 关键字。
如果是将结果赋值给const修饰的标识符时,const可以省略.
- 工厂构造方法(多个变量传入,返回同一个对象)
1.定义:使用factory关键字,用于通过工厂获取对象
2.使用:需要手动返回一个对象
main(List<String> args) {
var p1 = Person('why');
var p2 = Person('why');
print(identical(p1, p2));
}
class Person {
String name;
String color;
static final Map<String, Person> _namecache = {};
static final Map<String, Person> _colorcache = {};
factory Person(String name) {
if (_namecache.containsKey(name)) {
return _cache[name];
} else {
final p = Person._internal(name,'default');
_namecache[name] = p;
return p;
}
}
Person._internal(this.name,this.color);
}
setter和getter(监控类属性被访问的过程)
main(List<String> args) {
final d = Dog("黄色")
d.setColor = "黑色"
print(d.getColor)
}
class Dog {
String color
String get getColor {
return color
}
set setColor(String color) {
this.color = color
}
Dog(this.color)
}
类的继承
1.使用 extends 关键字,字类中使用super来访问父类;
2.父类中的所有成员变量和方法都会被继承,,但是构造方法除外;
main(List<String> args) {
var p = new Person();
p.age = 18;
p.run();
print(p.age);
}
class Animal {
int age;
run() {
print('在奔跑ing');
}
}
class Person extends Animal {
}
3.子类可以拥有自己的成员变量, 并且可以对父类的方法进行重写;
class Person extends Animal {
String name;
@override
run() {
print('$name在奔跑ing');
}
}
4.子类中可以调用父类的构造方法,对某些属性进行初始化;(方式:子类构造方法 :super(父类构造方法参数))
class Animal {
int age;
Animal(this.age);
run() {
print('在奔跑ing');
}
}
class Person extends Animal {
String name;
Person(String name, int age) : super(age);
@override
run() {
print('$name在奔跑ing');
}
}
抽象类(定义类)
没有具体实现的方法(没有方法体),就是抽象方法.
1.抽象方法,必须存在于抽象类中;
2.抽象类是使用abstract声明的类;
3.抽象类不能通过普通构造函数实例化,但是可以通过工厂构造函数实例化;
4.抽象类中的抽象方法必须被子类实现, 抽象类中的已经被实现方法, 可以不被子类重写
abstract class Shape {
getArea();
}
class Circle extends Shape {
double r;
Circle(this.r);
@override
getArea() {
return r * r * 3.14;
}
}
class Reactangle extends Shape {
double w;
double h;
Reactangle(this.w, this.h);
@override
getArea() {
return w * h;
}
}
5.external关键字可以使得方法的声明和实现分开,使用@patch注解实现。(可以针对不同平台不同实现)
隐式接口
1.应用场景:Dart中没有一个专门的关键字来声明接口,默认情况下,定义的每个类都相当于默认也声明了一个接口,可以由其他的类来实现(因为Dart不支持多继承),在开发中,我们通常将用于给别人实现的类声明为抽象类;
2.注意事项:通过implements实现某个类时,类中所有的方法都必须 被重新实现(无论这个类原来是否已经实现过该方法)。
3.使用: abstract class Runner {
run();
}
abstract class Flyer {
fly();
}
class SuperMan implements Runner, Flyer {
@override
run() {
print('超人在奔跑');
}
@override
fly() {
print('超人在飞');
}
}
Mixin混入(定义类)
1.出现场景:使用implements必须重新实现所有方法,但是某些情况下,某个类希望能直接复用之前类的原有实现方法(不能使用继承,只支持单继承,即复用一个类),即使用mixin混入方式。
2.使用:通过mixin定义一个类,用于被其他类混入使用,通过with关键字进行混入。
main(List<String> args) {
var superMan = SuperMain();
superMan.run();
superMan.fly();
}
mixin Runner {
run() {
print('在奔跑');
}
}
mixin Flyer {
fly() {
print('在飞翔');
}
}
class SuperMain with Runner, Flyer {
}
类成员和方法
1.使用:使用static关键字定义:
main(List<String> args) {
var stu = Student()
stu.name = 'why'
stu.sno = 110
stu.study()
Student.time = '早上8点'
Student.attendClass()
}
class Student {
String name
int sno
static String time
study() {
print('$name在学习')
}
static attendClass() {
print('去上课')
}
}
2.注意:
实例对象不能访问类成员和类方法
枚举类型(定义类)
- 定义(表示固定数量的常量值)//通常分用于表示一个变量有几种可能的取值
使用enum关键字
main(List<String> args) {
print(Colors.red);
}
enum Colors {
red,
green,
blue
}
- 属性
1.index:表示每个枚举常量的索引,从0开始;
2.values:包含每个枚举值的list。
3.使用:
main(List<String> args) {
print(Colors.red.index);
print(Colors.green.index);
print(Colors.blue.index);
print(Colors.values);
}
enum Colors {
red,
green,
blue
}
4.注意:不能子类化、混合或实现枚举;
不能显式实例化一个枚举。
08-泛型
- List和Map的写法
List<String> names3 = ['why', 'kobe', 'james', 111]
Map<String, String> infos2 = {'name': 'why', 'age': 18}
- 泛型类定义
main(List<String> args) {
Location l2 = Location<int>(10, 20)
print(l2.x.runtimeType)
Location l3 = Location<String>('aaa', 'bbb')
print(l3.x.runtimeType)
}
class Location<T> { // 假如希望类型只是num类型:class Location<T extends num>
T x
T y
Location(this.x, this.y)
}
- 泛型方法定义
main(List<String> args) {
var names = ['why', 'kobe']
var first = getFirst(names)
print('$first ${first.runtimeType}')
}
T getFirst<T>(List<T> ts) {
return ts[0]
}
09-库的使用
- 导入
1.语法: import '库所在的url'
2.关于库url形式:
1)dart标准库:dart:io dart:html dart:math
2)相对路径导入即自己项目中定义的其他dart文件
3)Pub包管理工具管理的库(我理解的类似于npm): import 'packsge:flutter/material.dart'
3.库文件部分内容
1)show:显示某个成员(屏蔽其他)
import 'lib/student/student.dart' show Student, Person;
2)hide:隐藏某个成员(显示其他)
import 'lib/student/student.dart' hide Person;
4.库文件内容与当前文件名字冲突,使用as
import 'lib/student/student.dart' as Stu;
Stu.Student s = new Stu.Student();
- 定义
- library关键字
library math
- part关键字(库文件太大,拆分库) //官方不推荐使用
part "mathUtils.dart";
part "dateUtils.dart";
- export关键字
utils.dart文件
library utils;
export "mathUtils.dart";
export "dateUtils.dart";
test_libary.dart文件
import "lib/utils.dart";
main(List<String> args) {
print(sum(10, 20));
print(dateFormat(DateTime.now()));
}