[TOC]
前言 如果你只是写界面可能你看Flutter的Widget就够了。
可是当你写业务的时候,你不去了解Dart语言那么你讲寸步难行。
本文致力于以最小的篇幅介绍Flutter的敲门砖:Dart最必备的基础知识。
一、变量 1、变量定义 1 2 3 4 int b = 10 ;String s = "hello" ;var a = 1 ;dynamic c = 0.5 ;
可以明确指定某个变量的类型,如int bool String,也可以用var或 dynamic来声明一个变量,Dart会自动推断其数据类型。
dynamic 则是告诉编译器,我们知道自己在做什么,不用做类型检测 。
2、变量类型检测 为了在运行时检测进行类型检测,Dart 提供了一个关键字 is:
1 2 3 4 5 6 7 8 dynamic obj = {};if (obj is Map ) { obj['foo' ] = 42 ; } var map = obj as Map ;
3、类型互转 3.1 String与int互转 1 2 int .parse("100" );123. toString();
二、函数 1、函数的写法 以下三种函数的写法,都是正确的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int add(int a, int b) { return a + b; } add2(int a, int b) { return a + b; } add3(a, b) => a + b; main() { print (add(1 , 2 )); print (add2(2 , 3 )); print (add3(1 , 2 )); }
所有的函数都有返回值,如果没有指定return语句,那么该函数的返回值为null。
1.1、类方法/实例方法 1 2 3 4 5 6 7 8 9 Class A { int method1(int x); static int method2(int y); } a = A().method1(1 ); b = A.method2(2 );
2、函数的参数(可选/默认值/必选) 2.1、基本的函数参数写法 1 2 3 4 5 6 7 8 void main() { print (defalut_foo1(1 , 2 )); } int defalut_foo1(int x, int y) { return x + y; }
2.2、标记参数为可选/默认值 知识点:
①要设置参数的默认值,只有该参数为可选的时候,才能够设置。
②参数可选的方法有两种,常规的参数加上[],或者使用具名参数
1、常规的参数加上[],标记为可选
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void main() { print (option_foo1(1 )); print (option_foo1(1 , 1 )); print (option_foo1(1 , 1 , 1 )); } int option_foo1(int x, [int y, int z]) { int iResult = x; if (y != null ) { iResult += 10 *y; } if (z != null ) { iResult += 100 *z; } return iResult; } int option_foo2(int x, [int y = 0 ]) { return x + y; }
2、使用具名参数(named parameters),使得参数为可选
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int named_foo1({int x, int y}) { return x + y; } int named_foo2({int x = 0 , int y = 0 }) { return x + y; } void main() { print (named_foo1(x: 1 , y: 2 )); print (named_foo1(y: 3 , x: 4 )); print (named_foo1()); print (named_foo2(x: 1 , y: 2 )); print (named_foo2()); }
2.3、如果想告诉用户某个参数是必须的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int require_foo1(@required int x, @required int y) { return x + y; } int require_foo2({@required int x, @required int y}) { return x + y; } void main() { print (require_foo1(1 , 2 )); print (require_foo2(x:1 , y:2 )); }
3、回调/函数做参数/返回值 3.1、回调 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 typedef ClickCallBack = int Function (int x, int y);String onButtonPress1(int a, int b, ClickCallBack callback) { int iResult = callback(a, b); return iResult.toString(); } void main() { String string = onButtonPress1(1 , 2 , (x, y) { return x + y; }); print ("string = " + string); }
3.2、函数参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 typedef Adder = int Function (int , int );String Function (String msg) cancelHandle;Adder makeAdder1(int extra) { int adder(int x, int y) { return x + y + extra; } return adder; } Adder makeAdder2(int extra) { return (x, y) => x + y + extra; } void main() { var adder1 = makeAdder1(2 ); print (adder1(1 , 2 )); var adder2 = makeAdder2(2 ); print (adder2(1 , 2 )); }
4、函数类型 Dart是一个面向对象的编程语言,所以即使是函数也是一个对象,也有一种类型Function,这就意味着函数可以赋值给某个变量或者作为参数传给另外的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 printNum(int a) { print ("$a"); } test(Function callback) { callback(" hello" );} main() { var f1 = printNum; Function f2 = printNum; var f3 = (int a) => print ("a = $a"); f1(1); f2(2); f3(6); }
三、类 1、类的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class User { String name; int age; String gender; String get uid => "24210853532539238" ; set right(String uid) => left = value - width; User(this .name, this .age, this .gender); User.defaultUser() { name = "dvlp" ; age = 20 ; } sayHello() { print ("hello, this is $name , I am $age years old, I am a $gender"); } // 成员方法写法2:没有方法体(是抽象方法,需要子类去实现) void doSomething(); } // 抽象类(无法实例化的类),如果希望抽象类看起来是可实例化的,请定义工厂构造函数。 // 抽象类通常有抽象方法,如下: // 此类声明为abstract,因此是抽象类,即也就无法实例化 abstract class Test { //定义构造函数,字段,方法... // 抽象方法 void test(); }
说明类中的构造方法Person(this.name, this.age, this.gender);
的这种语法是Dart比较独特而简洁的构造方法声明方式,它等同于下面的代码:
1 2 3 4 5 User(String name, int age, String gender) { this .name = name; this .age = age; this .gender = gender; }
其他声明成员变量的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 class Rectangle { num left, top, width, height; Rectangle(this .left, this .top, this .width, this .height); num get right => left + width; set right(num value) => left = value - width; num get bottom => top + height; set bottom(num value) => top = value - height; }
2、类的使用 1 2 3 4 5 6 7 8 main() { var user1 = new Person("zhangsan" , 20 , "male" ); user.age = 30 ; user.gender = "female" ; user.sayHello(); var user2 = new Person.defaultUser() }
当我们调用一个不存在的方法时,会执行 noSuchMethod() 方法,默认情况下它会抛出 NoSuchMethodError。你也可以重写noSuchMethod()
,改成你输出你希望的错误提示
1 2 3 4 5 6 7 8 9 10 class Test { @override void noSuchMethod(Invocation invocation) { print ('You tried to use a non-existent member: ' + '${invocation.memberName} ' ); } }
3、类的继承 Dart中使用extends关键字做类的继承。
1 2 3 4 5 6 class Developer extends User { void doSomething() { print ("I'm developing..." ); } }
虽然 Dart 是单继承的,但它也提供了一定程度的多重继承支持:
使用@override
注解声明你要重写的函数,在这个函数内部可以使用super调用重写的这个父类的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class FlutterDeveloper extends Developer { @override void doSomething() { super .doSomething(); print ("I'm developing Flutter..." ); } } class iOSDeveloper extends Developer { @override void doSomething() { super .doSomething(); print ("I'm developing iOS..." ); } } class FullStackDeveloper extends Developer with iOSDeveloper with FlutterDeveloper { @override void doSomething() { super .doSomething(); print ("I'm developing..." ); } }
mixins mixins是一个重复使用类中代码的方式,比如下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class A { a() { print ("A's a()" ); } } class B { b() { print ("B's b()" ); } } class C = A with B ;main () { C c = new C(); c.a(); c.b(); }
四、库 1 2 3 4 5 6 7 8 9 import './util.dart' ;import 'package:lib2/lib2.dart' as lib2;import 'package:greetings/hello.dart' deferred as hello;
1、问题一:在同一工程中可否有两个同名的类 1 2 3 4 5 6 7 8 import 'package:lib1/lib1.dart' ;import 'package:lib2/lib2.dart' as lib2;Element element1 = Element ();lib2.Element element2 = lib2.Element ();
2、问题二、如何只允许/只不允许使用某个包中的部分功能 1 2 3 4 5 import 'package:lib1/lib1.dart' show foo;import 'package:lib2/lib2.dart' hide foo;
五、运算符 1、常见的
运算符
含义
++var
var=var+1
表达式的值为var+1
var++
var=var+1
表达式的值为var
--var
var=var-1
表达式的值为var-1
var--
var=var-1
表达式的值为var
++a
a == b
b ? a : b
2、特殊的 2.1、..运算符(级联操作) 使用..调用某个对象的方法(或者成员变量)时,返回值是这个对象本身,所以你可以接着使用..调用这个对象的其他方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Person { eat() { print ("I am eating..." ); } sleep() { print ("I am sleeping..." ); } study() { print ("I am studying..." ); } } main() { new Person()..eat() ..sleep() ..study(); }
六、控制流程
语句
说明
if / else
略
switch
略(switch 也支持 String 和 enum)
for /while
略
try / catch
略
1 2 3 4 5 6 7 8 9 10 11 12 13 String a = "hello" ; switch (a) { case "hello" : print ("haha" ); break ; case "world" : print ("heihei" ); break ; default : print ("WTF" ); }
七、异步 如果一个方法中有耗时的操作,你需要将这个方法设置成async,并给其中的耗时操作加上await关键字,如果这个方法有返回值,你需要将返回值塞到Future中并返回,如下代码所示:
1 2 3 4 Future<String > checkVersion() async { var version = await lookUpVersion(); return version; }
八、其他/奇技淫巧 1、静态成员变量和静态成员方法 1 2 3 4 5 6 7 8 9 10 11 12 class Cons { static const name = "zhangsan" ; static sayHello() { print ("hello, this is ${Cons.name} " ); } } main() { Cons.sayHello(); print (Cons.name); }
2、修饰符final和const final 跟 Java 里的 final 一样,表示一个运行时常量(在程序运行的时候赋值,赋值后值不再改变)。const 表示一个编译时常量,在程序编译的时候它的值就确定了。
修饰符
作用
final
一个被final修饰的变量只能被赋值一次,
const
一个被const修饰的变量是一个编译时常量(const常量毫无疑问也是final常量)
final和const的区别:
区别一:final 要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而 const 要求在声明时初始化,并且赋值必需为编译时常量。
区别二:final 是惰性初始化,即在运行时第一次使用前才初始化。而 const 是在编译时就确定值了。
3、泛型 1 var names = List <String >();
附 其他参考文档: