一、函数
1.1 函数的基本定义
Dart是一种真正的面向对象语言,所以即使函数也是对象,所有也有类型, 类型就是Function。
函数的定义方式:
返回值 函数的名称(参数列表) {
函数体
return 返回值
}
例子:
int sum(num num1, num num2) {
return num1 + num2;
}
//Effective Dart建议对公共的API, 使用类型注解, 但是如果我们省略掉了类型, 依然是可以正常工作的
sum(num1, num2) {
return num1 + num2;
}
//如果函数中只有一个表达式, 那么可以使用箭头语法(arrow syntax)
sum(num1, num2) => num1 + num2;
1.2 函数的参数问题
函数的参数可以分成两类: 必须参数和可选参数
前面使用的参数都是必须参数.
1.2.1 可选参数
可选参数可以分为 命名可选参数 和 位置可选参数
命名可选参数: {param1, param2, ...}
位置可选参数: [param1, param2, ...]
命名可选参数:
// 命名可选参数
printInfo1(String name, {int age, double height}) {
print('name=$name age=$age height=$height');
}
// 调用printInfo1函数
printInfo1('why'); // name=why age=null height=null
printInfo1('why', age: 18); // name=why age=18 height=null
printInfo1('why', age: 18, height: 1.88); // name=why age=18 height=1.88
printInfo1('why', height: 1.88); // name=why age=null height=1.88
位置可选参数
// 定义位置可选参数
printInfo2(String name, [int age, double height]) {
print('name=$name age=$age height=$height');
}
// 调用printInfo2函数
printInfo2('why'); // name=why age=null height=null
printInfo2('why', 18); // name=why age=18 height=null
printInfo2('why', 18, 1.88); // name=why age=18 height=1.88
//命名可选参数, 可以指定某个参数是必传的
printInfo3(String name, {int age, double height, @required String address}) {
print('name=$name age=$age height=$height address=$address');
}
1.2.2 参数默认值
参数可以有默认值, 在不传入的情况下, 使用默认值
// 参数的默认值
printInfo4(String name, {int age = 18, double height=1.88}) {
print('name=$name age=$age height=$height');
}
Dart中的main函数就是一个接受可选的列表参数作为参数的, 所以在使用main函数时, 我们可以传入参数, 也可以不传入
1.3 函数是一等公民
在很多语言中, 函数并不能作为一等公民来使用, 比如OC. 这种限制让编程不够灵活, 所以现代的编程语言基本都支持函数作为一等公民来使用, Dart也支持.
这就可以将函数赋值给一个变量, 也可以将函数作为另外一个函数的参数或者返回值来使用.
main(List<String> args) {
// 1.将函数赋值给一个变量
var bar = foo;
print(bar);
// 2.将函数作为另一个函数的参数
test(foo);
// 3.将函数作为另一个函数的返回值
var func =getFunc();
func('kobe');
}
// 1.定义一个函数
foo(String name) {
print('传入的name:$name');
}
// 2.将函数作为另外一个函数的参数
test(Function func) {
func('coderwhy');
}
// 3.将函数作为另一个函数的返回值
getFunc() {
return foo;
}
1.4 匿名函数
大部分我们定义的函数都会有自己的名字,但是某些情况下,给函数命名太麻烦了,我们可以使用没有名字的函数,这种函数可以被称之为匿名函数( anonymous function)
main(List<String> args) {
// 1.定义数组
var movies = ['盗梦空间', '星际穿越', '少年派', '大话西游'];
// 2.使用forEach遍历: 有名字的函数
printElement(item) {
print(item);
}
movies.forEach(printElement);
// 3.使用forEach遍历: 匿名函数
movies.forEach((item) {
print(item);
});
movies.forEach((item) => print(item));
}
1.5 词法的作用域
dart中的词法有自己明确的作用域范围,它是根据代码的结构({})来决定作用域范围的
优先使用自己作用域中的变量,如果没有找到,则一层层向外查找。
var name = 'global';
main(List<String> args) {
// var name = 'main';
void foo() {
// var name = 'foo';
print(name);
}
foo();
}
1.6 闭包
闭包可以访问其词法范围内的变量
main(List<String> args) {
makeAdder(num addBy) {
return (num i) {
return i + addBy;
};
}
var adder2 = makeAdder(2);
print(adder2(10)); // 12
print(adder2(6)); // 8
var adder5 = makeAdder(5);
print(adder5(10)); // 15
print(adder5(6)); // 11
}
1.7 返回值
所有函数都返回一个值。如果没有指定返回值,则语句返回null;隐式附加到函数体。
main(List<String> args) {
print(foo()); // null
}
foo() {
print('foo function');
}
二、运算符
2.1 除法、整除、取模运算
var num = 7;
print(num / 3); // 除法操作, 结果2.3333..
print(num ~/ 3); // 整除操作, 结果2;
print(num % 3); // 取模操作, 结果1;
2.2 ??=赋值操作
当变量为null时,使用后面的内容进行赋值。
当变量有值时,使用自己原来的值。
main(List<String> args) {
var name1 = 'susu';
print(name1);
// var name2 = 'kobe';
var name2 = null;
name2 ??= 'james';
print(name2);
}
2.3 条件运算符 ??
如果expr1是null,则返回expr2的结果;
如果expr1不是null,直接使用expr1的结果。
var temp = 'why';
var temp = null;
var name = temp ?? 'kobe';
print(name);
2.4 级联语法 ..
对一个对象进行连续的操作可以使用级联语法
class Person {
String name;
void run() {
print("${name} is running");
}
void eat() {
print("${name} is eating");
}
void swim() {
print("${name} is swimming");
}
}
main(List<String> args) {
final p1 = Person();
p1.name = 'why';
p1.run();
p1.eat();
p1.swim();
final p2 = Person()
..name = "why"
..run()
..eat()
..swim();
}
三、流程控制
3.1if 、else
和其他语言用
注意点:不支持非空即真或者非0即真,必须有明确的bool类型
3.2 循环操作
//for
for (var i = 0; i < 5; i++) {
print(i);
}
//for in
var names = ['why', 'susu', 'run'];
for (var name in names) {
print(name);
}
while和do-while和其他语言一致
break和continue用法也是一致
3.3 switch-case
main(List<String> args) {
var direction = 'east';
switch (direction) {
case 'east':
print('东面');
break;
case 'south':
print('南面');
break;
case 'west':
print('西面');
break;
case 'north':
print('北面');
break;
default:
print('其他方向');
}
}
四、类和对象
Dart是一个面向对象的语言,面向对象中非常重要的概念就是类,类产生了对象。
4.1 类的定义
在Dart中,定义类用class
关键字。
类通常有两部分组成:成员(member)和方法(method)。
class 类名 {
类型 成员名;
返回值类型 方法名(参数列表) {
方法体
}
}
//:
class Person {
String name;
eat() {
print('$name在吃东西');
}
}
main(List<String> args) {
// 1.创建类的对象
var p = new Person(); // 直接使用Person()也可以创建
// 2.给对象的属性赋值
p.name = 'susu';
// 3.调用对象的方法
p.eat();
}
4.2 构造方法
4.2.1 普通构造方法
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@override
String toString() {
return 'name=$name age=$age';
}
}
在实现构造方法时,通常做的事情就是通过参数给属性赋值
为了简化这一过程, Dart提供了一种更加简洁的语法糖形式
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 等同于
Person(this.name, this.age);
4.2.2 命名构造方法
因为不支持方法(函数)的重载,所以我们没办法创建相同名称的构造方法,所以需要命名构造方法
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);
或者
// 新的构造方法
Person.fromMap(Map<String, Object> map) {
this.name = map['name'];
this.age = map['age'];
}
// 通过上面的构造方法创建对象
var p3 = new Person.fromMap({'name': 'susu', 'age': 27});
print(p3);
4.2.3 初始化列表
class Point {
final num x;
final num y;
final num distance;
// 错误写法
// Point(this.x, this.y) {
// distance = sqrt(x * x + y * y);
// }
// 正确的写法
Point(this.x, this.y) : distance = sqrt(x * x + y * y);
}
4.2.4 重定向构造方法
一个构造方法中去调用另外一个构造方法, 这个时候可以使用重定向构造方法
class Person {
String name;
int age;
Person(this.name, this.age);
Person.fromName(String name) : this(name, 0);
}
4.2.5 工厂构造方法
main(List<String> args) {
var p1 = Person('susu');
var p2 = Person('susu');
print(identical(p1, p2)); // true
}
class Person {
String name;
static final Map<String, Person> _cache = <String, Person>{};
factory Person(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final p = Person._internal(name);
_cache[name] = p;
return p;
}
}
Person._internal(this.name);
}
4.3 setter 和 getter
默认情况下,Dart中类定义的属性是可以直接被外界访问的。
但是某些情况下,我们希望监控这个类的属性被访问的过程,这个时候就可以使用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);
}
4.4 类的继承
Dart中的继承使用extends关键字,子类中使用super来访问父类。
父类中的所有成员变量和方法都会被继承,,但是构造方法除外。
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 {
}
子类可以拥有自己的成员变量, 并且可以对父类的方法进行重写
class Person extends Animal {
String name;
@override
run() {
print('$name在奔跑ing');
}
}
子类中可以调用父类的构造方法,对某些属性进行初始化
class Animal {
int age;
Animal(this.age);
run() {
print('在奔跑ing');
}
}
class Person extends Animal {
String name;
Person(String name, int age) : name=name, super(age);
@override
run() {
print('$name在奔跑ing');
}
@override
String toString() {
return 'name=$name, age=$age';
}
}
4.5 隐式接口
在开发中,我们通常将用于给别人实现的类声明为抽象类
abstract class Runner {
run();
}
abstract class Flyer {
fly();
}
class SuperMan implements Runner, Flyer {
@override
run() {
print('susu在奔跑');
}
@override
fly() {
print('susu在飞');
}
}
4.6 类成员和方法
在Dart中我们使用static关键字来定义
main(List<String> args) {
var stu = Student();
stu.name = 'why';
stu.sno = 110;
stu.study();
Student.time = '早上8点';
// stu.time = '早上9点'; 错误做法, 实例对象不能访问类成员
Student.attendClass(); // stu.attendClass(); 错误做法, 实现对象不能访问类方法
}
class Student {
String name;
int sno;
static String time;
study() {
print('$name在学习');
}
static attendClass() {
print('去上课');
}
}
4.7 枚举
4.7.1 枚举定义
使用enum关键字
main(List<String> args) {
print(Colors.red);
}
enum Colors {
red,
green,
blue
}
4.7.2 枚举的属性
index: 用于表示每个枚举常量的索引, 从0开始.
values: 包含每个枚举值的List.
main(List<String> args) {
print(Colors.red.index);
print(Colors.green.index);
print(Colors.blue.index);
print(Colors.values);
}
enum Colors {
red,
green,
blue
}
五、泛型
5.1 List和Map的泛型
//List
// 创建List的方式
var names1 = ['why', 'kobe', 'susu', 111];
print(names1.runtimeType); // List<Object>
// 限制类型
var names2 = <String>['why', 'kobe', 'susu', 111]; // 最后一个报错
List<String> names3 = ['why', 'kobe', 'susu', 111]; // 最后一个报错
//Map
// 创建Map的方式
var infos1 = {1: 'one', 'name': 'why', 'age': 18};
print(infos1.runtimeType); // _InternalLinkedHashMap<Object, Object>
// 对类型进行显示
Map<String, String> infos2 = {'name': 'why', 'age': 18}; // 18不能放在value中
var infos3 = <String, String>{'name': 'why', 'age': 18}; // 18不能放在value中
5.2 类定义的泛型
main(List<String> args) {
Location l1 = Location(10, 20);
print(l1.x.runtimeType); // Object
}
class Location {
Object x;
Object y;
Location(this.x, this.y);
}
5.3 泛型方法
main(List<String> args) {
var names = ['why', 'susu'];
var first = getFirst(names);
print('$first ${first.runtimeType}'); // why String
}
T getFirst<T>(List<T> ts) {
return ts[0];
}
网友评论