flutter是dart语言开发的一个移动开发ui框架,dart语言与其他各种高级语言非常类似。下面记录一些与c++或java不一样的语法。
Dart语言特点
- dart语言可以开发 Web、移动端、PC、服务器端、物联网等平台应用
- 面向对象,一切皆对象,强类型
num:数值变量类型
字符串常量:用'-'或"_"
字符串插值:用$varName或${varName}引用字符串
var:动态(dynamic)类型变量,一旦定义类型就确定下来(个人建议少用),如
var a; //dynamic类型变量
a=10; //第一次赋值为int,则后续都为int
a="adfadf"; //error
方法定义 (TODO:修订)
- 顶级方法:定义在类外,类似于c++中的全局方法,
- 静态方法:类中的静态方法,和c++一样
- 实例方法:类的成员方法,和c++一样
- 嵌套方法:定义在方法中的方法
变量定义:与方法类似,有顶级变量,静态变量,实例变量(属性)
dart只有公有和私有两种权限控制分类,以"_"开头的标识符在库内私有。
Dart 工具可以指出两种问题:警告和错误。 警告只是说你的代码可能有问题, 但是并不会阻止你的代码执行。 错误可以是编译时错误也可以是运行时错误。遇到编译时错误时,代码将 无法执行;运行时错误将会在运行代码的时候导致一个 异常。
未被初始化的变量,其值都为null。
final与const:都表示静态变量,const需要在编译时就需要赋值,final将赋值推迟到运行时,第一次赋值之后就不能改变了。
const还可以用来创建静态构造函数,这样的构造函数创造的值不能改变。
Keywords(关键字)
下表为 Dart 语言的关键字。
abstract 1 | continue | false | new | this |
---|---|---|---|---|
as 1 | default | final | null | throw |
assert | deferred 1 | finally | operator 1 | true |
async 2 | do | for | part 1 | try |
async 2* | dynamic 1 | get 1 | rethrow | typedef 1 |
await 2 | else | if | return | var |
break | enum | implements 1 | set 1 | void |
case | export 1 | import 1 | static 1 | while |
catch | external 1 | in | super | with |
class | extends | is | switch | yield 2 |
const | factory 1 | library 1 | sync 2* | yield 2* |
带有上标 1 的关键字是内置关键字,避免把内置关键字当做标识符使用,也不要把内置关键字用作类名字和类型名字。 有些内置关键字是为了方便把 JavaScript 代码移植到 Dart 而存在的。 例如,如果 JavaScript 代码中有个变量的名字为 factory
, 在移植到 Dart 中的时候,你不必重新命名这个变量。
带有上标 2 的关键字,是在 Dart 1.0 发布以后又新加的,用于支持异步相关的特性,不能在标记为 async
、 async*
、或者 sync*
的方法体内 使用 async
、 await
、或者 yield
作为标识符。 详情请参考:异步支持。
所以其他单词都是 保留词。 你不能用保留词作为关键字。
内置类型
1、数值类型
num,int( -253 和 253 ),double(双精度浮点),int和double是num的子类。
2、字符串
Dart 字符串是 UTF-16 编码的字符序列。 可以使用单引号或者双引号来创建字符串,用$varName或${varName}引用字符串,支持+,==操作,用三个单引号包含创建多行字符。
3、布尔类型
bool,与c++不同的是,bool变量只有为true时,才为真,其他都为假,就算1也为假。
4、列表
List a=[1,2,3];
5、表
map,与c++ stl中map类似,不同的是构造增加了这种构造方法
var nobleGases = {
// Keys Values
2 : 'helium',
10: 'neon',
18: 'argon',
};
6、符号(Runes)
用于在字符串中表示 Unicode 字符,在 Dart 中,runes 代表字符串的 UTF-32 code points。
Unicode 为每一个字符、标点符号、表情符号等都定义了 一个唯一的数值。 由于 Dart 字符串是 UTF-16 code units 字符序列, 所以在字符串中表达 32-bit Unicode 值就需要 新的语法了。
通常使用 \uXXXX
的方式来表示 Unicode code point, 这里的 XXXX 是4个 16 进制的数。 例如,心形符号 (♥) 是 \u2665
。 对于非 4 个数值的情况, 把编码值放到大括号中即可。 例如,笑脸 emoji (😆) 是 \u{1f600}
。
String 类 有一些属性可以提取 rune 信息。 codeUnitAt
和 codeUnit
属性返回 16-bit code units。 使用 runes
属性来获取字符串的 runes 信息。
7、Symbols
一个 Symbol object 代表 Dart 程序中声明的操作符或者标识符。使用 Symbol 字面量来获取标识符的 symbol 对象,也就是在标识符 前面添加一个 #
符号。不懂,不用
Function类型
方法也是一种类型,方法可以赋值给变量,也可以作为参数传递给另一个方法,实现回调。
对于只有一个表达式的方法,你可以选择 使用缩写语法来定义:(鸡肋)
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
参数
普通参数
//声明
int foo(int a,int b){}
//调用
foo(1,2);
可选命名参数
//声明
int foo({int a,int b}){}
//调用
foo(a:1);
foo(a:1,b:2);
可选位置参数
//声明
int foo(int a,[int b])
//调用
foo(1);
foo(1,2);
参数默认值
//声明
int foo(int a=1,int b=2){}
//调用
foo();
匿名方法
即lambda表达式
作用域
大括号内定义的变量只能大括号没访问,大括号内可以方位大括号前面定义的变量。
返回值、
没指定返回值会自动插入return null作为最后个语句。
操作符
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+ | - | - | * | / | ~/ | % | == | != | > | < | >= | <= | as | is | is! |
= | += | -= | *= | /= | ~/= | %= | >>= | <<= | &= | I= | ^= | ! | ll | && | & |
l | ^ | ~ | << | >> | ?: | ?? | .. | () | [] | . | ?. |
比较特别的有
操作符 | 用法 | 说明 |
---|---|---|
/ | a/b | 除法操作,返回double |
~/ | a~/b | 求商操作,返回整数 |
% | a%b | 取余操作,返回整数 |
is | if(a is b) | 判断a类似是否是b类型的,只有当 obj 实现了 T 的接口, obj is T 才是 true。例如 obj is Object 总是 true。 |
is! | if(a is! b) | 相当于if ( ! ( a is b ) ) |
as | (a as b).name() | 将a的类型转换为b,无法转换(类似于不是继承关系)则抛出异常 |
?? | int a=b??c; | 类似于?:,如果b为non-null,返回b,否则返回c |
.. | list..add(1)..add(2) | 级联操作。第一个表达式返回一个 selector 对象。 后面的级联操作符都是调用这个对象的成员, 并忽略每个操作的返回值。级联操作可以嵌套 |
?. | foo?.bar | 如果foo为null则发挥null,则返回成员bar |
流程控制
控制方法 | 说明 |
---|---|
if else | 条件分支 |
for | for循环 |
while | while循环 |
do while | do while 循环 |
switch case | 开关,与c++不同的是case可以是int,string或者编译时常量,另外,如果某个非空case的处理结束没有break,就会报错(c++中不会报错,而是继续执行下个case直到遇到break)。 |
break | 跳出循环或者switch |
continue | 继续下一次循环 |
assert | 断言,只在调试模式下有效,发布模式无效,调试模式如果条件不满足,就会抛出异常 |
遍历
foreach
实现了iterable接口的类可以使用foreach进行遍历,如:
List<int> list=[1,2,3];
list.foreach((item)=>print(item));
for-in
某些实现了iterable的类还支持for-in遍历,类似于c++中的(for :)遍历
var list=[1,2,3];
for(var x in list){
print(x);
}
Exception(异常)
throw
抛出异常,可以抛出预定义异常,也可以抛出任何任何对象作为异常
throw new FormatException();
throw "this is a exception";
try-catch/on
try内可以尝试执行某个语句块,然后用catch或on或同时使用捕获该语句块中的异常并处理,on指定异常类型,catch的参数指定捕获到的异常,如果没有on,则可以捕获任意类型的异常。on-catch可以有多个。
rethrow
rethrow可以将异常重新抛出,给上层处理。
finally
finally在异常处理语句之后,无论是否捕获到异常,finally中的语句都会被执行。如果有异常但是没有对应catch来处理,则处理完finally之后,异常继续抛出。
一个综合的栗子(TODO:修订)
class MyException{
String what="this is a exception";
};
void foo(){
print("run foo");
throw MyException;
}
void bar(){
try{
print("run bar");
foo();
}catch(e){
print(e.what);
rethrow;
}finally{
print("bar over");
}
}
void main(){
try {
foo();
}catch(e){
print(e.what);
}
class(类)
与c++中不同的地方如下
单继承
dart中的类是单继承的,都最终继承自object类
this和super
this指向当前对象,super指向父类对象。
构造函数语法糖
如果构造函数只需要给成员赋值,可以简化为:
class ClassName{
ClassName(this.a,this.b);
int a;
int b;
}
等价于
class ClassName{
ClassName(int x,int y){
a=x;
b=y;
}
int a;
int b;
}
Redirecting constructors(重定向构造函数)
有时候一个构造函数会调动类中的其他构造函数。 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。
class Point {
num x;
num y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
Constant constructors(常量构造函数)
如果你的类提供一个状态不变的对象(即一旦定义就不能修改成员,只能访问)你可以把这些对象 定义为编译时常量。要实现这个功能,需要定义一个 const 构造函数, 并且声明所有类的变量为 final。
class ImmutablePoint {
final num x;
final num y;
const ImmutablePoint(this.x, this.y);
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
}
Factory constructors(工厂方法构造函数)
如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义 这个构造函数。例如,一个工厂构造函数 可能从缓存中获取一个实例并返回,或者 返回一个子类型的实例。
下面代码演示工厂构造函数 如何从缓存中返回对象。
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to the _ in front
// of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = new Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) {
print(msg);
}
}
}
注意: 工厂构造函数无法访问 this。
使用 new 关键字来调用工厂构造函数。
var logger = new Logger('UI');
logger.log('Button clicked');