前言:
最近学习flutter,发现怎么都绕不过dart, 于是就学习了一下dart,在此做个总结,本章节只讲跟Java不同的地方, 相同的地方一笔带过。
1、变量定义
main() {
// 基本类型
var a = 10; // 可变类型,和JavaScript里面一样, 类型会自动转换
var aa = "aaaaaa";
var aaa = true;
int b = 10;
String c = "hello";
dynamic d = "aaaaa"; // 跟var一样
dynamic e = 10;
dynamic f = 10.0;
bool is = true;
final String g = "aaa"; // 赋值后就不能改变
final h = 10; // 赋值为整型, 不写类型表示可以赋值为各种类型
static const i = "aaa"; // 必须是static, 否则会报错,const必须直接被初始化成常量
num j = 3; // 数字类型, 无论是整型还是小数都可以
String k = "aaa"; // 跟Java声明变量一样
// List的操作
List
在Dart中一切都是对象,都继承于Object,例如整型转字符串: int a = 3; String b = a.toString();
Dart是强类型语言,但是它又兼容JavaScript的var,类型可以自己推断, Dart支持泛型
Dart没有public、protected、private等关键字,如果一个变量以下划线开头表示变量私有
Dart变量可以以字母开头,由字母数字下划线组成
2、函数
Dart声明方法和Java的类似,它可以不指明返回值, 但是还是推荐指明,当方法只有一条语句,并且return这条语句的时候可以用=>来代替.
不论在Dart还是Flutter中,都有一个main函数,它是应用的入口函数,返回值是void,还有一个可选参数,参数类型是List
所有的函数都有返回值,如果没有指定return语句,那么该函数的返回值为null
// 声明返回值
int add(int a, int b) {
return a + b;
}
// 不声明返回值, 但是不推荐
add2(int a, int b) {
return a + b;
}
// 只有一条语句,并且返回这条语句
add3(int a, int b) => a + b;
// 只有一条语句,并且返回这条语句, 变量类型可以不写, 接收多种类型
add3(a, b) => a + b;
// 中括号表示参数可以不传, 是可选参数
add4(int a, int b, [int c]) {
}
main() {
print(add(1, 2));
print(add2(1, 2));
print(add3(1, 2));
}
函数其实可以作为一个对象传递给另一个对象, 这个类似于oc里面的块代码
// dart中可以通过$加变量名来显示变量的值
printString(int a) {
print("$a");
}
main() {
List list = ["aaa", "bbb", "ccc"];
// 列表对象都有一个forEach方法, 里面需要传一个方法,意思是把每一个元素取出来传给这个方法
list.forEach(printString);
var fun1 = printString;
fun1("hhhhhhhhhhh"); // 相当于引用了printString方法
// fun2指向了一个匿名方法,这个匿名方法有一句代码
var fun2 = (int a) => print("a = $a");
// 上面代码可以写成:
var fun2 = (int a) {
print("a = $a");
}
// 没有参数:
var fun3 = () {
print("aaaa");
}
}
3、操作符
操作符大多数都跟Java一样,只有个别不一样, 现在我们看看有哪些不一样:
// is运算符用于判断一个变量是不是某个类型的数据
// is!则是判断变量不是某个类型的数据
var s = "hello";
print(s is String); // true
var num = 6;
print(num is! String); // true
// ~/才是取整运算符,如果使用/则是除法运算,不取整
int k = 1;
int j = 2;
print(k / j); // 0.5
print(k ~/ j); // 0
// as运算符类似于Java中的cast操作,将一个对象强制类型转换
(emp as Person).teach();
// ??=运算符 如果 ??= 运算符前面的变量为null,则赋值,否则不赋值
var param1 = "hello", param2 = null;
param1 ??= "world";
param2 ??= "world";
print("param1 = $param1"); // param1 = hello
print("param2 = $param2"); // param2 = world
// ?.运算符
var str1 = "hello world";
var str2 = null;
print(str1?.length); // 11
print(str2?.length); // null
print(str2.length); // 报错
.. 运算符:级联运算符,跟Java中的build模式特别像
class Person {
eat() {
print("I am eating...");
}
sleep() {
print("I am sleeping...");
}
study() {
print("I am studying...");
}
}
main() {
// 依次打印
// I am eating...
// I am sleeping...
// I am studying...
new Person()..eat()
..sleep()
..study();
}
4、流程控制(if-else switch for while等等都跟Java一样,唯独try-catch稍微有点不太一样)
// 捕获所有异常
try {
List
5、类
class Person {
String name;
int age;
String sex;
Person(this.name, this.age, this.sex);
sayHello() {
print("hello, this is $name, I am $age years old, I am a $sex");
}
}
Person类中有3个成员变量,一个构造方法和一个成员方法,看起来比较奇怪的是Person的构造方法,里面传入的3个参数都是this.xxx,而且没有大括号{}包裹的方法体,这种语法是Dart比较独特而简洁的构造方法声明方式,它等同于下面的代码:
Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex= sex;
}
要调用Person类的成员变量或成员方法,可以用下面的代码:
var p = new Person("zhangsan", 20, "male");
p.sayHello(); // hello, this is zhangsan, I am 20 years old, I am a male
p.age = 50;
p.sex= "female";
p.sayHello(); // hello, this is zhangsan, I am 50 years old, I am a female
类除了有跟类名相同的构造方法外,还可以添加命名的构造方法,如下代码所示:
class Point {
num x, y;
Point(this.x, this.y);
// 类的命名构造方法, 方法名可以自己随便取
Point.origin() {
x = 0;
y = 0;
}
}
main() {
// 调用Point类的命名构造方法origin()
var p = new Point.origin();
var p2 = new Point(1, 2);
}
跟Java一样,dart也是用extends关键字来继承:如果一个类只有命名的构造方法,在继承时需要注意,如下代码:
class Human {
String name;
Human.fromJson(Map data) {
print("Human's fromJson constructor");
}
}
class Man extends Human {
Man.fromJson(Map data) : super.fromJson(data) {
print("Man's fromJson constructor");
}
}
由于Human类没有默认构造方法,只有一个命名构造方法fromJson,所以在Man类继承Human类时,需要调用父类的fromJson方法做初始化,而且必须使用Man.fromJson(Map data) : super.fromJson(data)这种写法,而不是像Java那样将super写到花括号中。
类里面的set get方法:
class Persion {
int x, y;
num a, b;
Persion() {} // 经测试类里面只能有一个这种构造函数,它不能与下面带参的构造函数共存
// Persion(this.x, this.y); // 有我没上面的
Persion.origial(Map map) { // 可以和上面的任意一个构造函数共存
x = 10;
y = 12;
}
// 这是get方法的固定写法, getX函数名是自己取的
// int 表示返回值, get表示这是get方法, getx是函数名, 后面是函数的实现
int get getx => x + y;
int get gety { // 等同于上面的写法
return x+y;
}
// 这是set方法的固定写法, setX函数名是自己取的
// 函数返回null, set表示这是set方法, setX是函数名, 后面是函数的实现
set setX(int xx) => x = xx - y;
set setY(int yy) { // 等同于上面
y = xx - y;
}
}
抽象类和抽象方法:跟Java差不多
使用abstract修饰一个类,则这个类是抽象类,这个类必须被继承,抽象类中可以有抽象方法和非抽象方法,抽象方法没有方法体,需要子类去实现
abstract class Doer {
// 抽象方法,没有方法体,需要子类去实现
void doSomething();
// 普通的方法
void greet() {
print("hello world!");
}
}
class EffectiveDoer extends Doer {
// 实现了父类的抽象方法
void doSomething() {
print("I'm doing something...");
}
}
枚举
和Java类似
enum Color { red, green, blue }
with的用法:
class A {
a() {
print("A's a()");
}
}
class B {
b() {
print("B's b()");
}
}
// 使用with关键字,表示类C是由类A和类B混合而构成
class C = A with B;
main() {
C c = new C();
c.a(); // 输出:A's a()
c.b(); // 输出:B's b()
}
静态成员和静态方法:
// 跟Java一样,静态成员变量和方法可以用类名直接访问
// 类的静态成员变量和静态成员方法
class Cons {
static const name = "zhangsan";
static sayHello() {
print("hello, this is ${Cons.name}");
}
}
main() {
Cons.sayHello(); // hello, this is zhangsan
print(Cons.name); // zhangsan
}
注意: 类实例化变量的时候可以省掉前面的new, 直接"类名()"来实例化
6、泛型(和Java类似)
7、方法的命名参数
printName({String name}) {
print("hello, my name is $name");
}
printName2({name: String}) {
print("hello, my name is $name");
}
main() {
// 打印 hello, my name is dongjie
printName(name: 'dongjie');
// 打印 hello, my name is xiaoli
printName2(name: 'xiaoli');
}
从上面例子中可以看到,定义命名参数时,你可以以 {type paramName}
或者 {paramName: type}
两种方式声明参数,而调用命名参数时,需要以 funcName(paramName: paramValue)
的形式调用。
命名参数的参数并不是必须的,所以上面的代码中,如果调用printName()不带任何参数,也是可以的,只不过最后打印出来的结果是:hello, my name is null,在Flutter开发中,你可以使用@required注解来标识一个命名参数,这代表该参数是必须的,你不传则会报错
7、匿名方法
匿名方法的定义:
(参数1,参数2,....){
方法体...
return 返回值
}
void main(List args) {
var func = () {
print("Hello");
};
func();
var func1 = (str) {
print("Hello-------$str");
};
func1("huangxiaoguo");
// 通过()进行调用,不推荐使用
(() {
print("通过()进行调用,不推荐使用");
})();
//匿名方法传参
var list2 = ['h', 'e', 'l', 'l', 'o'];
print(listTimes(list2, (str) {
return str * 3;
}));
}
List listTimes(List list, String times(str)) {
for (var i = 0; i < list.length; i++) {
list[i] = times(list[i]);
}
return list;
}
输出:
Hello
Hello-------huangxiaoguo
通过()进行调用,不推荐使用
[hhh, eee, lll, lll, ooo]
8、Dart引用外部文件
如果你要使用的类或者代码在其他的文件中,则需要把它引进来,通过import
import 'package:flutter/material.dart';
import './util.dart';
import '../dart:html'; // 两个点代表上一级
可以使用as关键字为导入的某个包设置一个前缀,或者说别名,比如下面的代码:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
上面的没懂? 看个例子:我引用了http库,调用里面的方法:
也可以在导入包时使用show hide关键字来导入某个包中的部分功能,比如下面的代码:
// 只导入foo
import 'package:lib1/lib1.dart' show foo;
// 导入除了foo的所有其他部分
import 'package:lib2/lib2.dart' hide foo;
导入包时使用deferred as可以让这个包懒加载,懒加载的包只会在该包被使用时得到加载,而不是一开始就加载,比如下面的代码:
import 'package:greetings/hello.dart' deferred as hello;
9、异步操作
Dart提供了async await等异步操作,这种异步操作在Flutter开发中会经常遇到,比如网络或其他IO操作。
async和await往往是成对出现的,如果一个方法中有耗时的操作,你需要将这个方法设置成async,并给其中的耗时操作加上await关键字,如果这个方法有返回值,你需要将返回值塞到Future中并返回:
import 'dart:async';
import 'package:http/http.dart' as http;
Future getNetData() async{
http.Response res = await http.get("http://www.baidu.com");
return res.body;
}
main() {
getNetData().then((str) {
print(str);
});
}