# 1. 开始
# 1.1 入口函数
首先是入口函数 main (程序的入口), void 指明该函数的返回值为空或者说没有返回值
void main(){
print('hello world')
}
# 2. 数据类型
# 2.1 var 和 dynamic
var 声明的变量(在编译时期)会自动推断变量类型
比如你这个人很懒,类型都不想写,所以写出来的代码是下面这坨(这个字自己领会)
var a = 123;
var v = "123";
这两行代码在编译之后其实是有类型的和如下代码一样的效果
num a = 123;
String v = "123";
一个类型一旦确定就不可以变成其他类型
var a = 123;
a="123"; //此时编辑器就会飘红告诉你说 ‘一个String类型的值不能赋值给一个int类型的变量’
偏偏有些时候,代码是这样的
var a;
a = '123';
a = 123;
这个代码是完全可以跑起来的,怎么回事?前面不是说'一个类型一断确定就不可以变成其他类型',其实这句话没错,错的是'var a;'这句没法推断出类型啊,所以就按dynamic类型来处理的。dynamic就是它的字面意思。dynamic 会关闭类型检查,它声明的变量类型在运行时才会确定。
dynamic a = "123";
a = 456;
a.foo(); // 这一句在我们写代码的时候完全不会提示有错误,在代码运行的时候走到这里就会crash
# 2.2 const 和 final
在 dart 里 const 和 final 都是用来定义常量的,那为啥子定义个常量要搞两个关键词尼?其实区别是 const 是编译时常量,而 final 是运行时常量。
const 关键字定义的常量在代码中写死。
const num w = 300;
w = 200; // 此时编辑器会提示 w是个常量不能赋值,要么移除w定义前面的const关键字,要么移除 这行代码。
final 关键字定义该值只能被赋值一次。只是它的具体的值在编译期可以为null 待到运行时才确定。
void foo(int a){
final int aa = a;
print(aa);
}
foo(123);
foo(456);
foo(789);
# 2.3 数据类型
number 类型: num int double int 和 double 继承 num
int a = 12;
a.isEven // true
a.isOdd // false
double b = 6.5;
常用方法有 toDouble、 toInt、 round、 ceil、 floor
字符串 String
String str1 = 'test \n test';
String str2 = r'test \n test'; // r会使转义失效 python中也有这个r
可以先javascript es6中一样使用模板字符串(稍有区别)
String split= '-----';
String str3 = 'test${split}test';
String str4 = '123$split';
print(str3);
布尔 boolean
bool isLoading = false;
数组 List
List list= [];
list.add(123);
List list1= new List(5);
print(list1)
list.asMap() // 转换成 map 类型
键值对 map
Map m = {1:123,2:456};
print(m[1])
Map m2 = new Map()
// 常用属性
m2.length
m2.isEmpty // 返回布尔值
m2.isNotEmpty // 返回布尔值
m2.keys // 返回素有的键
m2.values // 返回所有的值
//常用方法
m2.containsKey(1)
m2.containsValue(123)
# 3.运算符
# 3.1 算术运算
加、减、乘、除、取整、取余
int a = 11;
int b = 2;
print(a + b);
print(a - b);
print(a * b);
print(a / b);
print(a ~/ b); // python中是双斜线 //
print(a % b);
print(a++);
print(a);
print(++a);
print(a--);
print(a);
print(--a);
# 3.2 赋值运算
dart 中有个比较风骚的赋值操作符 ??=
int a;
int b = 2;
a?? = 10; // a 为 null 吗? 是:将 10 赋值给 a; 不是:不进行操作。双问号起短路作用
b?? = 2;
print(a);
print(b)
另外就是一些很平常的赋值操作
int a = 10;
int b = 5;
a += 2;
print(a);
a -= 5;
print(a);
a *= 2;
print(a);
// a /= 2;
a ~/= 2;
a %= 2;
# 3.3 条件表达式(三目运算)
int color;
int nowColor= color == null ?'red':color;
// 在dart中 ?? 操作符可以简化这种操作
int nowColor = color??'red'
# 3.4 逻辑运算
与或非
bool isTrue = true;
print(!isTrue);
bool isFalse = false;
print(isTrue && isFalse);
print(isTrue || isFalse);
String str = '';
print(!str.isEmpty);
# 3.5 关系型运行算符
关系型运算符常用来比较两个值之间的关系返回true或false,常用在流程控制语句中。
int a = 5;
int b = 4;
print(a == b);
print(a != b);
print(a > b);
print(a < b);
print(a >= b);
print(a <= b);
String str1 = '123';
String str2 = '123';
print(str1 == str2);
# * 4. 流程控制语句
if switch for while (do while) break continue
# 5. 函数
dart是强类型的语言,在函数的声明(定义)时,要明确指定参数的数据类型以及该函数的返回值类型,没有返回值时返回值类型是 void
String getAllName(String firstName,String secondName){
return '${firstName}-${secondName}';
}
函数的类型是 Function , 可以将函数当作参数传入到调用的函数中,也可以调用一个函数返回一个新的函数(有关闭包)
doSomething((String name){
print(name);
});
void doSomething(void callback(String name)){
callback('123');
}
int a = 10;
Function fn = getSomeFn()
fn();
void getSomeFn(){
int a = 123;
return (){
print(a);
};
}
匿名函数,顾名思义匿名函数就是没有名字的函数。在上面的 getSomeFn 中已经出现过了匿名函数。下面是一些立即执行的匿名函数
// 写法一
((a) {
print(a);
}(123));
// 写法二
(a) {
print(a);
}(456);
// 写法三
((a) {
print(a);
})(789);
函数参数之可选参数。
dart 提供非常灵活的传参方式,这对编程体验来非常棒;dart 中函数的可选参数需要用 {} 包裹,放在必选参数的后面。
fn1('bing', 18);
fn2('bing');
void fn1(String name, int age) {
print('name=$name,age=$age');
}
void fn2(String name, {int age}) {
print('name=$name,age=$age');
}
函数参数之默认值。
在上面可选参数的示例中如果可选参数没有传则默认为 null ,有些时候这可不是我们想要的,这时候可以给可选参数设置默认值,当没有传该值的时候参数会自动取默认值。
fn2('bing');
void fn2(String name, {int age = 18}) {
print('name=$name,age=$age');
}
值得注意的是 必选参数 在传值的时候必须按照参数列表的顺序 而可选参数则不必,但是 必须 以 ‘参数名:值’的方式传值。
# 6. 面向对象
在面向对象的语言设计中,对象通常是类的实例,而类(class)则是对象的一种抽象,描述这一类对象具有的属性和行为特征。
# 6.1 类的申明、对象创建、属性、方法、可见性、计算属性
在dart中描述一个类需要使用 class 关键字,而实例化一个对象则需要使用 new 关键字来说明是新建一个对象(注意:在dart 2 中可以将new 关键字省略)
class Person{
// 一些 属性和行为
}
Person xiaoming = new Person()
Person xiaowang = Person()
类中的属性会默认生成 getter setter 方法,当对一个实例的某个属性赋值或者取值时其实是调用的setter getter方法。
class Person{
String name;
int age;
}
Person xiaoming= new Person();
xiaoming.name = "wangxiaoming";
xiaoming.age=19;
print(xiaoming.name);
print(xiaoming.age);
私有属性,私有方法。 dart 中没有private等关键字,目前在类中设置一个私有属性是通过 _ 的方式
class Person{
String _secret;
void _run(){
print('xxx')
}
}
我们也可以给类加上 _ ,表是该类只在当前文件(模块)中可以访问到。
计算属性。 计算属性的值当然是通过计算得到的
Rectangle rect = new Rectangle();
rect.height = 20;
rect.width = 10;
print(rect.area);
class Rectangle {
num width, height;
num get area => width * height;
set area(value) { //给area属性赋值时,可以计算出其他属性的值
width = value / 20;
}
}
# 6.2 构造方法、命名构造方法、常量构造方法、工厂构造方法
构造函数和类同名,在类初始化的时候调用用来给对象成员赋初始值
class Person {
String name;
Person(String name){
this.name = name
}
}
首先dart中构造方法并不能重载,如果一个类中要实现多个构造方法可以使用命名构造方法。
class Person{
String name;
int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
Persom.withName(String name){
this.name = name;
}
Person.withAge(int age){
this.age = age;
}
}
常量构造函数,能够生成一个不再改变的对象。构造函数用const修饰,所有的属性采用 final 修饰。前面说过const 修饰的常量是编译时常量 。创建编译时常量只需要在调用构造函数 前加上 const 关键字即可。如果已经在一个常量上下文中那么调用构造函数前的const关键字可以省略。
两个用相同参数生成的常量对象其实是同一个对象
更多关于常量构造函数的讲解或示例可以到官方文档查看.
class Person{
final String name;
final int age;
const Person(this.name,this.age)
}
const Person p = const Person('bing',18);
const Person p2 = Person('bing',18);
p==p2 // true
工厂构造方法,在实现构造函数时添加 factory 关键字实现一个工厂构造方法。工厂函数额调用和普通函数的调用一样。(工厂构造方法中不能访问 this )
Logger logger = Logger('test')
logger.log('Button clicked');
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(
name, () => Logger._internal(name));
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
# 6.3 初始化列表、静态成员、操作符、call方法
在构造函数的函数体运行前,除了调用父类的构造方法,还可以初始化实例的变量。有时,当类的某些属性是 final 属性时,初始化列表将很有帮助。
class Person {
String name;
int age;
final String gender;
Person(this.name, this.age, this.gender);
Person.withMap(Map map) : gender = map['gender'] {
this.name = map['name'];
this.age = map['age'];
}
Person.withMap2(Map map)
: gender = map['gender'],
name = map['name'] {
this.age = map['age'];
}
void work() {
print('work');
}
}
*注意在初始化列表的右侧不能访问this
// 右侧指的时 等号 的右边 map['gender']
Person.withMap(Map map) : this.gender = map['gender']
dart 中类的静态成员使用static关键字修饰。静态成员直接通过 className.xxx 来访问。静态变量在初次访问时初始化,静态方法中不能访问类实例this。
class Page {
static const int max = 10;
static int now = 1;
static void pullDown() {
now = 1;
}
void pullUp() {
now++;
}
}
print(Page.max)
对象操作符
// 1. 条件成员访问 ?.
Person person;
person?.work(); // person存在时调用work
// 2. 类型转换
var p; // 前面说过var 在运行时会推断类型,但是没有初始值的时候 var 和 dynamic 一样 ,所以下面的 as 就是类型转换
p = "";
p = new Person();
(p as Person).work();
//3. 是否指定类型 is,is!
var p2;
p2 = '';
if (p2 is Person) {
p2.work();
}
if (p2 is! Person) {
print('ohohoo');
}
// 4.级联操作 .. (..会返回原对象)
Person pp = new Person();
pp
..name = "bing"
..age = 21
..work();
call , 对象中实现call方法后,对象的实例可以看作一个方法来调用。
Person p = new Person();
p.work();
p('bing', 30);
class Person {
String name;
int age;
void work() {
print('work...');
}
void call(String name, int age) {
print('my name is $name,and my age is $age');
}
}
# 6.4 继承 抽象 接口 mixinxs 操作符重载
类的继承通过 extends 实现, 子类可以继承父类的属性和方法。子类也可以通过‘重写’的形式修改某个方法的实现。
class Person{
String name;
void job(){
print('job')
}
}
class Student extends Person{
void job(){
print('my job is study')
}
}
abstract 关键字可以定义一个抽象类(不能被实例化),目前在dart中这可以用来定义一个接口(dart中并没有interface关键字来专门定义接口)。除了抽象类还可以有抽象方法,抽象方法只能出现在抽象类中,并且没有方法体,用';'代替方法体。
abstract class Animal{
void eat();
}
dart 的类中都隐式的定义了接口,该接口包含了类的所有实例成员。如果只是先把一个类当作接口来用 使用 implements 关键字,并且实现所有类中的接口。
除了继承这种代码的复用方式,dart中还可以使用混入的方式来进行代码复用;使用方法是:with关键字后面跟多个用逗号分隔的类名或者混入对象的名称(dart2.1之前都是使用抽象类代替)
mixin Play{
void play(){
print('play game')
}
}
class Student extends Person with Play{
}
dart 的类中还支持操作符的重载,具体使用如下:
var p1 = new Person(18);
var p2 = new Person(20);
print(p2 > p1);
print(p2['age']);
class Person {
int age;
Person(this.age) {}
bool operator >(Person p) {
return this.age > p.age;
}
int operator [](String str) {
if ('age' == str) {
return age;
}
return 0;
}
}