Dart语言特点:
Dart中,一切(数字类型、方法、null等)都是对象,一切对象都是class的实例,所有的对象都是继承自Object
Dart支持范型,List<int>表示一个整型的数据列表,List<dynamic>则是一个对象的列表,其中可以装任意对象
Dart支持顶层方法(如main方法),也支持类方法或对象方法,同时你也可以在方法内部创建方法
Dart支持顶层变量,也支持类变量或对象变量
Dart没有public protected private等关键字,
Dart中若某个变量以下划线_ 开头,代表这个变量在库中是私有的
打印语法:
print(#s == new Symbol("s"));// 打印:true
var clapping = '\u{1f44f}';
print(clapping); // 打印的是拍手emoji的表情
print(add(1,1)); // 打印 调用函数 的返回值
sayHello({String name}) {
print("这是一个有 命名参数的函数: $name"); //打印函数的参数
}
一、变量与常量
变量声明与默认值:没有赋初值的变量都会有默认值null
int b = 10;
String s = "hello";
var a = 1; //变量,自动推断其数据类型
dynamic c = 0.5; //对象,自动推断其数据类型
final 和 const
var count = 10;
const Num1 = 10; // const赋值必须是编译时常量,编译时就确定值了
final Num2 = count; // final 只能赋值一次,赋的值不一定是编译时常量;在运行时第一次使用前才初始化
二、数据类型
数字:
var a = 0;
int b = 1;
double c = 0.1;
字符串:
var s1 = 'hello';
String s2 = "world";
布尔:
var real = true;
bool isR = false;
数组:
var arr = [1, 2, 3, 4, 5]; //自动推断为 数字数组
List<String> arr2 = ['hello', 'world', "123", "456"]; //字符串数组
List<dynamic> arr3 = [1, true, 'haha', 1.0];//对象数组
字典:
var map = new Map();
map['name'] = 'zhangsan';
map['age'] = 10;
Map m = new Map();
m['a'] = 'a';
字符集: runes
Dart 中 使用runes 来获取UTF-32字符集的字符。
String的 codeUnitAt and codeUnit属性可以获取UTF-16字符集的字符
var clapping = '\u{1f44f}';
print(clapping); // 打印的是拍手emoji的表情
符号: symbols:
print(#s == new Symbol("s"));// 打印:true
三、函数
Dart中的函数也有一种类型 Function,函数可以作为参数传递,也可以赋值给某个变量;
1.函数的返回值
//声明函数返回值类型
int add(int a, int b){
return a + b;
}
//不声明函数返回值类型
add2(int a, int b){
return a + b;
}
// return 返回语句的简写: =>
add3(a,b) => a + b;
//函数的调用
main(){
print(add(1,1)); // 2
print(add2(1,2)); // 3
print(add3(1,3)); // 4
}
2.函数的参数:
//===============命名参数===============
sayHello1({String name}) {
print("这是一个有 命名参数的函数: $name");
}
sayHello2({name: String}) {
print("带 命名参数 的函数的第二种写法:$name");
}
sayHello3({@required String name}) {
print("必须穿参数,否则报错:$name");
}
main(){
sayHello1(name:'张三'; // 这是一个有 命名参数的函数:张三
sayHello2(name:'李四'); // 带 命名参数 的函数的第二种写法: 李四
sayHello2();// 没有传参数,此时打印: 带 命名参数 的函数的第二种写法:null
sayHello3();// 不传参数 会报错
}
//===============位置参数===============
//位置参数用[] 包裹,可传可不传,放在参数列表的最后,可以是多个
sayHello(String name, int age, [String a, int b]){
StringBuffer sb = new StringBuffer(); // 可变字符串
sb.write("名字: $name 年龄:$age");
if(a != null){
sb.write("这是a: $a");
}
print(sb.toString());
}
main(){
sayHello("张三",20); // 打印: 名字:张三 年龄:20
sayHello("张三",20,"糖"); // 打印: 名字:张三 年龄:20 这是a:糖
}
//===============参数默认值===============
int add({int a, int b=3}){ //不能写成 int add({a: int, b: int = 3})
return a + b;
}
int sum(int a, int b, [int c=3]){
return a + b + c;
}
main{
print(add(1)); // 4 (?)
print(sum(1,1)); // 5 (?)
}
3.main()函数:
main()函数,应用入口函数,返回值是 void ,有一个可选参数,参数类型是List<String>
1.函数作为参数传递给另一个函数
printNum(int a){
print("$a");
}
main(){
var arr = [1,2,3];
arr.forEach(printNum);//将数组中的每一个元素都依次传入函数printNum中,依次打印:1、2、3
}
2.函数赋值给某个变量
printNum(int a){
print("$a");
}
main(){
var f1 = printNum;
Function f2 = printNum;
var f3 = (int a) => print("a = $a");
f1(1); // 1
f2(2); // 2
f3(6); // a = 6
}
3.匿名函数
没有名称的函数,类似于Java中的接口,一般在某个函数的参数为函数时使用到
test(Function callback) {
callback("hello"); // callback就是一个匿名函数
}
main(){
test((param){
print(param);//打印 hello
});
}
4.函数返回值
所有的函数都有返回值,如果没有指定return语句,那么该函数的返回值为null
四、运算符
运算符优先级: 每个运算符的优先级 都高于 后面行中的运算符。
main(){
//================与java相同的运算符操作================
var a,b;
a = 0;
b = ++a; // a:1 b:1 ++a 先++ 再赋值
b = a++; // a:2 b:1 a++ 先赋值 后++
print(a==b); // false
print(a*b);//2
bool real = false;
real ? print("真") : print("非真") // 非真
print(real && a== b);// false
print (real || a == 2);// true
print(a !=3); // true
print(a <= b); // false
var c = 9;
c += 10;
print("c = $c"); // c = 19
print(1<<2); // 4 左移运算符:将1的二进制向左移2位,变为100(十进制 4)
print(4>>2); // 1 右移运算符:将4的二进制向右移2位,变为1
//================与java不同的运算符操作================
1. is 与 is!
var s = "hello";
var num = 6;
print(s is String); // true is运算符用于判断变量是某个类型的数据
print(num is! String); // true is!运算符用于判断变量不是某个类型的数据
2. 除法 与取整
int k = 1;
int j = 2;
print(k / j); // 0.5 '/'运算符 是 除法运算 ,不取整
print(k ~/ j); // 0 '~/'运算符 取整
3.强制类型转换
//as 运算符 将对象转换为特定类型
if(emp is Person){ //如果 emp 是 Person 类型 赋值
emp.firstName = "ABC";
}
//如果 emp 不是 person类型 或为 空,上面什么都不做
//下方代码:如果emp为空 或不是Person类型,将抛出异常;如果emp是Person类型,给其赋值;
(emp as Person).firstName = "ABC";
4.为null时赋值
var p1 = "hello", p2 = null;
p1 ??= "world"; // 若 p1 为 null 则赋值,否则 不赋值
p2 ??= "world"; // 若 p2 为 null 则赋值,否则 不赋值
5.属性为空的判断
var str1 = "hello", str2 = null;
print(str1?.length); // 5 若 str1 有length 属性 则忽略'?'的作用
print(str2?.length); // null 若 str2 没有length的属性 则返回null
print(str2.length); // 报错
6.级联操作(.. 运算符)
使用'..'运算符调用对象的方法或成员变量,可以连续使用'..'运算符;但不能再返回 void 上构造级联
示例:
var button = queaySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
等价于:
querySelector('#confirm')
..text = 'Confirm'
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
也可以嵌套级联:
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
注意:在返回实际对象的函数上构造级联要小心返回的是否是void,在void上构造级联会报错
var sb = StringBuffer();
sb.write('foot') // 此时返回void
..write('bar'); //在void上构造级联会报错
}
五、控制流程
main(){
1. if-else语句
int score = 80;
if(score < 60){
print("不及格");
}else if(score >= 60 && score < 80){
print("良好");
}else{
print("优秀");
}
2. switch语句
String a = "hello";
switch (a) {
case "hello": // case 语句中的数据类型必须跟switch中的类型一致
print("是hello");
break;
case "world":
print("是world");
break;
default:
print("其他");
}
3. for 语句 (for-in)
List<String> list = ["a","b","c"];
for (int i = 0; i < list.length; i++){
print(list[i]);
}
for (var i in List){
print (i);
}
4. while 语句
int start = 1;
int sum = 0;
while(start <= 100){
sum += start;
start++;
}
print(sum);
5. try catch 语句
try{
pring(1 ~/ 0);
} catch(e){
print(e);
}
try{
1 ~/ 0;
} on IntegerDivisionByZeroException { // 铺货指定类型的异常
print("error");
} finally{
print("over");
}
}
六、类
Dart中的类没有 private/protected/public等访问控制,
1.类的定义
class Person{
//3个成员变量
String name;
int age;
String gender;
//1个构造方法
Person(this.name,this.age,this.gender);
//上方的构造方法 写法上等同于:
Person(String name, int age, String gender){
this.name = name;
this.age = age;
this.gender = gender;
}
//1个成员方法 : 成员方法是一个函数,为该类提供某些行为
sayHello(){
print("我叫 $name, 今年 $age岁,性别 $gender");
}
}
2.调用 Person 类的成员变量或成员方法
var p = new Person("张三",22,"男");
p.sayHello(); // 打印: 我叫 张三, 今年 22岁,性别 男
p.age = 25;
p.gender = "女";
p.sayHello(); // 打印:我叫 张三, 今年 25岁,性别 女
3.类的命名构造方法
class Point{
num x,y;
Point(this.x,this.y);
//类的命名构造方法
Point.origin(){
x=0;
y=0;
}
}
main(){
var p1 = new Point.origin();
var p1 = new Point(1,2);
}
4.在类的构造方法中,调用该类的另一个构造方法
class Point{
num x, y;
Point(this.x,this.y);
Point.alongXAxis(num x) : this(x, 0);
}
5.命名构造方法的继承问题
class Father {
String name;
Father.fromJson(Map data){ //父类中没有默认构造方法,只有这一个命名构造方法
print("这是父类的fromJson方法");
}
}
class Child extends Father{ //子类必须使用这种写法来调用父类的 fromJson方法做初始化
Child.fromJson(Map data) : super.fromJson(data) {
print("这是子类的fromJson方法")
}
}
6.类的成员方法
class Rectangle {
num left, top, width, height;
//构造方法
Rectangle(this.left, this.top, this.width, this.height);
//为 right 和 bottom两个成员变量提供 getter 和 setter 方法
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
7.抽象类 和 抽象方法
abstract class Doer { //使用 abstract 修饰的类,就是抽象类
void doSomething(); //没有方法体的方法 就是抽象方法,抽象方法需要子类去实现
void greet(){ // 有方法体的方法,是普通的 非抽象方法
print("hello world!");
}
}
class EffectiveDoer extends Doer {
void doSomething(){
print("实现父类的抽象方法,做一些事情")
}
}
8.枚举类
enum Color { red, green, blue}
9.运算符重载
class Vector {
num x, y;
Vector(this.x, this.y);
Vector operator + (vector v) => new Vector(x + v.x, y + v.y);
Vector operator - (vector v) => new Vector(x - v.x, y - v.y);
printVec(){
print("x: $x, y: $y");
}
}
main(){
Vector v1 = new Vector(1,2);
Vector v2 = new Vector(3,4);
(v1 - v2).printVec(); // -2, -2
(v1 + v2).printVec(); // 4, 6
}
10.合并两个类(mixins)
class A{
a(){
print(" 这是 A 的 a 方法");
}
}
class B{
b(){
print(" 这是 B 的 b 方法");
}
}
class C = A with B; //使用with 关键字,表示 类C 是由 类A 和 类B 混合而构成的
main(){
C c = new C();
C.a(); // 这是 A 的 a 方法
C.b(); // 这是 B 的 b 方法
}
11.静态成员变量和静态成员方法
class Cons {
static const name = "张三";
static sayHello(){
print("hello, 这是 ${Cons.name}");
}
}
main(){
Cons.sayHello(); // hello, 这是 张三
print(Cons.name);//张三
}
七、泛型
泛型可以减少代码的复杂度,Dart 内置的数据类型List就是一个泛型数据类型,可以往List中塞任何数据类型。
八、导入包和库
库:Libraries, Dart提供了很多功能库,只需要导入对应包即可
1.导入功能包
import 'dart:html';
2.引用其他.dart文件
使用相对路径引用:./ 或 ../
util.dart文件:
int add(int a, int b){
return a + b;
}
demo.dart文件
import './util.dart' //俩文件在同一目录下
main(){
print(add(1,2));
}
3.为导入的包设置一个别名
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2; // 使用 as 关键字 为包设置一个别名
// lib1 包中的 元素
Element element1 = Element();
// lib2 包中的元素
lib2.Element element2 = lib2.Element();
4.导入包中的部分功能
import 'package:lib1/lib1.dart' show foo; // 只导入lib1包中的 foo
import 'package:lib1/lib1.dart' hide foo; // 导入除了foo的所有其他部分
5.懒加载导入包
import 'package:greetings/hello.dart' deferred as hello; // 使用 deferred as 让hello包在使用时才加载
九、异步
异步操作:网络、输入输出、文件选择
如果一个方法中有耗时操作,需要将这个方法设置成 async ,并给其耗时操作加上 await 关键字
async 和 await 是成对出现的; 如果这个方法有返回值,需要将返回值塞到 Future 中并返回
Future<String> getNetData() async {
http.Response res = await http.get("http://www.baidu.com");
return res.body;
}
main(){
getNetData().then((str) { //获取网络数据 并打印出来
print(str);
});
}
网友评论