最近打算要入坑 Flutter,所以在此进行记录,随用随查;
不要怂,就是干,
一个简单的 Dart 程序
//🐷函数,应用从这里开始执行 main(){ var number = "Hello World"; printInteger(number); } //定义一个函数 printInteger(int aNumber){ print('The number is $aNumber'); }
重要的概念
在学习 Dart 语言时,应该基于以下事实和概念
任何保存在变量中的都是一个对象;所有的对象都对应一个类的实例,函数 和 null 都是对象,所有对象基于 Object 类
虽然 Dart 是强类型的,但是 Dart 可以进行类型推断,如上面代码变量 number 被推断为 int 类型;如果要明确说明不需要任何类型, 需要使用特殊类型 dynamic
Dart 支持泛型,如 List , List(任何类型的对象列表)
Dart 支持顶级函数 main() ,同样函数绑定在类或对象上(分别是 静态函数 和 实例函数 )。 以及支持函数内创建函数 ( 嵌套 或 局部函数 ) 。
Dart 支持顶级变量
dart 没有关键字 public ,protected 和 private,如果以 _ 开头,则相对于库是私有的
三目运算符:条件 condition ? Expr1 : expr2
类型问题:警告和错误,警告表示代码可能无法正常工作,但不会阻挡程序的执行,错误可能是编译或者运行时的错误,编译时错误会阻止代码的执行,运行时错误会导致代码在执行中引发异常(#exception)
关键字
应该避免这些单词作为标识符
带有 1 的单词为 上下文关键字,仅在特定位置具有含义,他们在任何地方都是有效标识符
带有 2 的为 内置标识符,这些关键字大多数地方都是有效的标识符,不能用于类型名称 和 import 前缀
带有 3 的是 Dart 1.0 发布后添加的异步支持相关的更新,作为限制类保留字。
变量
var name = "345"; //创建一个变量并初始化 dynamic name = "345"; // name 被推断为 String类型 String name = "345";//显式声明
dynamic:该类型具有所有可能的属性和方法,一个变量被 dynamic 修饰,相当于告诉系统,我知道这个类型到底是什么。使用后再编译时不会推断数据的类型,但是运行时会推断。
默认值
未初始化的变量默认值是 null,即使是数字类型也是 null。Dart 中一切皆是对象
Final 和 Const
使用过程中从来都不会被修改的变量,可用 final 或者 const。final 变量的值只能被设置一次,const 变量在编译时就已经固定。
内建类型
Number:有两种类型1,int,整数值不大于 64位;double 双精度浮点数
String::Dart 字符串是一组 UTF-16 单元序列,字符串通过单引号 或者 双引号创建
可使用 + 将字符串连接为一个;使用三个或三个双引号可实现多行字符串对象的创建
使用 r"" 前缀,可以创建“原始 raw 字符串”
Boolean: true and false
List:(也被称为 Array)
var list = [1, 2, 3]; var list = [1, 2, 3]; assert(list.length == 3); assert(list[1] == 2); list[1] = 1; assert(list[1] == 1);
在 list 之前添加 const 关键字,可定义 List 类型的编译时常量
Map:用来关联 key 和 value,同一个 map 中 key 只能出现一次
var constantList = const [1, 2, 3]; var gifts = { // Key: Value 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' };
Set:set 是一个元素唯一的集合
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'}; var names = <String>{}; // Set<String> names = {}; // 这样也是可以的。 // var names = {}; // 这样会创建一个 Map ,而不是 Set 。 var elements = <String>{}; elements.add('fluorine'); elements.addAll(halogens); var gifts = Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings'; var nobleGases = Map(); nobleGases[2] = 'helium'; nobleGases[10] = 'neon'; nobleGases[18] = 'argon';
Rune: (用于在字符串中表示 Unicode 字符)
在 Dart 中, Rune 用来表示字符串中的 UTF-32 编码字符
表示 Unicode 编码的常用方法是, \uXXXX, 这里 XXXX 是一个4位的16进制数。 例如,心形符号 (♥) 是 \u2665。 对于特殊的非 4 个数值的情况, 把编码值放到大括号中即可。 例如,emoji 的笑脸 (�) 是 \u{1f600}。
Symbol
Symbol 对象表示 Dart 程序中声明的运算符或者标识符,你一般不会使用到他
函数
Dart 是一门真正的面对对象语言,甚至其中的函数也是对象,并且有他的类型 Function。意味着函数可以被赋值给变量,或者作为参数传递给其他函数,也可以把 Dart 类的实例当做方法来调用
//省略类型声明,函数可以正常使用 isNoble(atomicNumber) { return _nobleGases[atomicNumber] != null; } //如果只有一句话,可简洁写法 bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=> *expr* 语法是 { return *expr*; } 的简写。 => 符号 有时也被称为 箭头 语法 ,箭头后面只能是一个表达式;
调用时可选参数
abc(bold: true, hidden: false);
可指定具体的参数值
const Scrollbar({Key key, @required Widget child})
使用 @required 表示参数是 required 性质的命名参数。
位置可选参数
String say(String from, String msg, [String device]) { var result = '$from says $msg'; if (device != null) { result = '$result with a $device'; } return result; }
将参数放在 [] 中,来标记参数是可选的。表示该参数可以不传
默认参数值
// bold 值为 true; hidden 值为 false. void abc(bool bold = false);
void doStuff( {List<int> list = const [1, 2, 3], Map<String, String> gifts = const { 'first': 'paper', 'second': 'cotton', 'third': 'leather' }}) { }
接受一个 list 和 map,并指定参数的默认值
main() 函数
void main(){ } // 这样运行应用: dart args.dart 1 test void main(List<String> arguments) { print(arguments); }
main 函数返回值为 空,参数为一个可选的 List
匿名函数
多数函数是有名字的,比如 main() 等,dart 可以创建没有名字的函数,这种函数被称为匿名函数,**有时候也被称为 lambda 或者 closure。**匿名函数可以赋值到一个变量中,例如:在一个集合中可以添加或者删除一个匿名函数
main(){ var list = []; list.add(1); list.add(2); list.add(3); list.add(4); list.forEach((num){ print('位置:${list.indexOf(num)} ;值:$num'); }); }
上面定义了一个 无类型参数num 的匿名函数,list 遍历时,每次都会调用这个函数,并将值传递给到匿名函数中。
如果只有一句话,可使用如下写法:
list.forEach((num)=>print('位置:${list.indexOf(num)} ;值:$num'));
函数的赋值与传递
main(){ //将匿名函数赋值给变量 var one = (num)=>print(' 值:$num'); one(10); //将普通函数赋值给变量 var two = abc; two(20); //将匿名函数传递给普通函数 abc2((str) => print("abc $str")); } void abc2(fun(String str)){ fun("输出-------》"); } void abc(num){ print("哈哈哈:$num"); }
词法作用域
dart 是一门词法作用域的编程语言。
简单的说变量的作用域在编写代码的时候就已经确定了,花括号内就是变量的可见作用域
bool topLevel = true; void main() { var insideMain = true; void myFunction() { var insideFunction = true; void nestedFunction() { var insideNestedFunction = true; assert(topLevel); assert(insideMain); assert(insideFunction); assert(insideNestedFunction); } } }
内部可以访问所有的变量,一直到顶级作用域内的变量。
词法闭包
闭包即一个函数对象。即使函数的调用在他原始的作用域之外,依然能访问他在词法作用域内的变量
/// 返回一个函数,返回的函数参数与 [addBy] 相加。 Function makeAdder(num addBy) { return (num i) => addBy + i; } void main() { // 创建一个加 2 的函数。 var add2 = makeAdder(2); // 创建一个加 4 的函数。 var add4 = makeAdder(4); assert(add2(3) == 5); assert(add4(3) == 7); }
测试函数是否相等
void foo() {} // 顶级函数 class A { static void bar() {} // 静态方法 void baz() {} // 示例方法 } void main() { var x; // 比较顶级函数。 x = foo; assert(foo == x); // 比较静态方法。 x = A.bar; assert(A.bar == x); // 比较实例方法。 var v = A(); // A的1号实例 var w = A(); // A的2号实例 var y = w; x = w.baz; // 两个闭包引用的同一实例(2号), // 所以它们相等。 assert(y.baz == x); // 两个闭包引用的非同一个实例, // 所以它们不相等。 assert(v.baz != w.baz); }
返回值
所有函数都会有返回值,如果没有明确返回值,函数体会被隐式的添加 return null;语句
运算符
Dart 定义的运算符如下:
上表中,多数运算符可被重载
条件表达式
*condition* ? *expr1* : *expr2*
如果条件为 true, 执行 expr1 (并返回它的值): 否则, 执行并返回 expr2 的值。
*expr1* ?? *expr2*
如果 expr1 是 non-null, 返回 expr1 的值; 否则, 执行并返回 expr2 的值。
级联运算符
级联运算符可以对一个对象进行一些了操作,除了调用函数,还可以访问同一对象上的字段属性,
void main() { new A() ..a1() ..a2(); } class A{ void a1(){ print('a1'); } void a2(){ print('a2'); } } //a1 a2
级联运算符可进行嵌套
final addressBook = (AddressBookBuilder() ..name = 'jenny' ..email = 'jenny@example.com' ..phone = (PhoneNumberBuilder() ..number = '415-555-0100' ..label = 'home') .build()) .build();
控制流程语句
if and else for loops for (var i = 0; i < 5; i++) { message.write('!'); }
也可使用 forEach,或者 for-in
candidates.forEach((candidate) => candidate.interview()); var collection = [0, 1, 2]; for (var x in collection) { print(x); // 0 1 2 }
while and do-while loops
break and continue
switch and case
和 java 基本类似,可以比较整数,字符串,或者编译时常量,比较的对象都是同一个实例(并且不能是子类),枚举也可以使用 switch 语句
assert
如果 assert 中的布尔条件为 false,那么正常的程序执行流程会被中断
assert 语句只在开发环境中有效,在生产环境是无效的
异常
Dart 可以抛出和捕获异常,如果没有被捕获,则会抛出,最终导致程序终止运行
和 Java 不同,Dart 中的所有异常时非检查异常,方法不会声明它们抛出的异常,也不要求捕获任何异常
Dart 提供了 Exception 和 Error 类型,以及一些子类型。也可以自定义异常类型。此外,Dart 程序可以抛出任何 非null 对象,不仅限 Exception 和 Error 对象。
throw
throw FormatException('Expected at least 1 section');
抛出任意的对象
throw 'Out of llamas!';
在使用表达式的地方抛出异常
void distanceTo(Point other) => throw UnimplementedError();
Catch
捕获异常
try { breedMoreLlamas(); } on OutOfLlamasException { // 一个特殊的异常 buyMoreLlamas(); } on Exception catch (e) { // 其他任何异常 print('Unknown exception: $e'); } catch (e) { // 没有指定的类型,处理所有异常 print('Something really unknown: $e'); }
catch 函数可以指定 1到2个参数,第一个为异常对象,第二个为堆栈信息(StackTrace对象)
try { // ··· } on Exception catch (e) { print('Exception details:\n $e'); } catch (e, s) { print('Exception details:\n $e'); print('Stack trace:\n $s'); }
如果部分异常需要处理,可使用 rethrow 将异常重新抛出
void misbehave() { try { dynamic foo = true; print(foo++); // Runtime error } catch (e) { print('misbehave() partially handled ${e.runtimeType}.'); rethrow; // Allow callers to see the exception. } } void main() { try { misbehave(); } catch (e) { print('main() finished handling ${e.runtimeType}.'); } }
finally
无论是否 try 住异常,finally 都会执行。如果 try 住异常,会先执行对应的 catch,最后执行 finally
类
Dart 是一种基于类和 mixin 继承机制的面向对象的语言,每个对象都是一个类的实例,所有的类都继承于 Object. 。 基于 * Mixin 继承* 意味着每个类(除 Object 外) 都只有一个超类, 一个类中的代码可以在其他多个继承类中重复使用。
创建对象
var p = Point(2, 2);
// 为实例的变量 y 设置值。 p.y = 3; // 获取变量 y 的值。 assert(p.y == 3); //如果 p 非空,则设置y=8 p?.y = 8 // 调用 p 的 distanceTo() 方法。 num distance = p.distanceTo(Point(4, 4));
使用 ?. 来代替 . , 可以避免因为左边对象可能为 null , 导致的异常
常量构造函数
var p = const ImmutablePoint(2, 2);
在构造函数名之前加 const 关机字,来创建编译时常量
注意:构造两个相同编译时常量会产生一个相同的实例
在常量上下文中,const 可以被省略:
// 这里有很多的 const 关键字。 const pointAndLine = const { 'point': const [const ImmutablePoint(0, 0)], 'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)], };
// 仅有一个 const ,由该 const 建立常量上下文。 const pointAndLine = { 'point': [ImmutablePoint(0, 0)], 'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)], };
需要在 Dart2中,一个常量上下文中的 const 关键字可以被省略
获取对象类型
使用对象的 runtimeType 属性, 可以在运行时获取对象的类型, runtimeType 属性回返回一个 Type 对象。
实例变量
class Point { num x; // 声明示例变量 x,初始值为 null 。 num y; // 声明示例变量 y,初始值为 null 。 num z = 0; // 声明示例变量 z,初始值为 0 。 }
未初始化的变量为 null
所有实例变量都隐式生成 getter 方法,非 final 的变量会生成 setter 方法
默认构造
没有声明构造时,Dart 会提供一个默认的构造
构造函数不被继承
子类不会继承父类的构造函数。 子类不声明构造函数,那么它就只有默认构造函数 (匿名,没有参数) 。
命名构造函数
使用命名构造函数可以为一个类实现多个构造函数,也可以使用命名构造函数来更清晰的表明函数意图:
class Point { num x, y; Point(this.x, this.y); // 命名构造函数 Point.origin() { x = 0; y = 0; } }
切记,构造函数不能够被继承, 这意味着父类的命名构造函数不会被子类继承。 如果希望使用父类中定义的命名构造函数创建子类, 就必须在子类中实现该构造函数。
调用父类field默认构造函数
执行顺序如下:
initializer list (初始化参数列表) superclass’s no-arg constructor (父类的无名构造函数) main class’s no-arg constructor (主类的无名构造函数) class Person { String firstName; Person.fromJson(Map data) { print('in Person'); } } class Employee extends Person { // Person does not have a default constructor; // you must call super.fromJson(data). Employee.fromJson(Map data) : super.fromJson(data) { print('in Employee'); } } main() { var emp = new Employee.fromJson({}); // Prints: // in Person // in Employee if (emp is Person) { // Type check emp.firstName = 'Bob'; } (emp as Person).firstName = 'Bob'; }
常量构造函数
class ImmutablePoint { static final ImmutablePoint origin = const ImmutablePoint(0, 0); final num x, y; const ImmutablePoint(this.x, this.y); }
工厂构造函数
class Logger { final String name; bool mute = false; // 从命名的 _ 可以知, // _cache 是私有属性。 static final Map<String, Logger> _cache = <String, Logger>{}; factory Logger(String name) { if (_cache.containsKey(name)) { return _cache[name]; } else { final logger = Logger._internal(name); _cache[name] = logger; return logger; } } Logger._internal(this.name); void log(String msg) { if (!mute) print(msg); } }
其实就是一个工厂模式,传如对于的 name,然后获取到对应的实例
关于其他的
抽象类,枚举,这些就不详细的说了,都是基本操作,和java差不多。如果不懂,可自行到官网查看
本文参考自:官方文档