变量和内置的类型
Final and const
- 如果您从不打算更改变量,请使用final或const,而不是var或者一个类型。 final变量只能设置一次; const变量是编译时常量。 (Const变量是隐式final的。)final的顶级或类变量在第一次使用时被初始化
- 实例变量可以是final的,但是不能是const的,且final的实例变量必须在构造函数前初始化;
- const修饰符不仅可以修饰变量,还可以修饰一个常量值,以及修饰一个创建常量值的构造函数;任何变量都可以被赋予一个const常量值
//const修饰变量
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere
//const修饰常量值
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`
-
在创建const常量的声明时,可以省略赋值时的初始化表达式中的const,比如上面的baz常量的创建
-
即使一个非final和非const的变量曾经被赋值了一个const常量,但是还是可以改变其值;相反,const修饰的常量不能被修改值
-
一个类能够定义 const 构造函数的前提是成员变量必须都是用final或const修饰的,调用该构造函数时,用const代替new,表示对象的状态完全可以在编译期间确定,并且完全是不可变的
-
const导致的不可变性是可传递的,如果你有一个final修饰的成员变量,这个成员变量包含了一个集合,那么这个集合仍然是可变的。如果包含的是const修饰的集合,那么集合内的所有东西是递归地不可变的
第一处打印[4,2,3],第二处打印将会报错 -
相同的const变量不会在内存中重复创建,如果表达式被调用了多次,则重用之前创建好的常量,那可以理解成const修饰的常量是单例模式吗?(按照原作者的回复,由于const的不可变性,所以这里的还不仅仅是单例,且是运行时不可以修改的单例)
String
- Dart中的string是utf-16编码的
- 字符串可以使用单引号,也可以使用双引号
- 字符串拼接可以使用+ ,也可以直接将相邻的两个拼接:
var s1 = 'String '
'concatenation'
" works even over line breaks.";
assert(s1 ==
'String concatenation works even over '
'line breaks.');
var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');
- 创建多行字符串还可以使用三个单引号或者三个双引号开始并结尾:
var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";
- 文字字符串是编译时常量,只要任何插值表达式是一个编译时常量,其值为null或数值,字符串或布尔值。
// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
Lists
Dart中的数组是List类型的对象,所以很多人就直接称其为lists,
var list = [1, 2, 3];
上面的list类型是List<int>,所以添加非int类型的元素会编译报错
- 创建一个编译时的常量list,需要在常量字面值之前添加const,当然,这之后,该变量是无法修改其中的数组元素值的:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // Uncommenting this causes an error.
spread operator (…) 和null-aware spread operator (…?)
在Dart2.3中,加入了传播操作符… ,和空感知的传播操作符?..
这提供了一种插入多个元素到一个集合中的简便方式:
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
- 从Dart2.3开始,可以使用‘if’和‘for’条件语句来创建集合,如:
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
Set
Dart中的set集合是无序、且元素不可重复的,在Dart 2.2开始,加入了Set 字面值,下面使用set literal字面值创建了一个set,集合类型为Set<String>
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set. it's type is Map<dynamic, dynamic>.
- Dart先引入了map, 所以看似set和map的语法相似,以上创建空的集合时,不指明类型,Dart默认其类型为 Map<dynamic, dynamic>
- 创建一个编译时常量set集合,可以在set集合字面值前添加const:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.
Maps
Dart中的map,key可以是任何类型;创建一个编译时常量map,可以在map字面值前添加const:
//直接创建一个map
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
//使用构造函数创建map
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
//创建编译时常量
final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};
Runes
Dart中的字符串是UTF-16编码的,在转换为32位的Unicode编码时,需要特定的语法
Functions
- 定义命名参数函数时,参数列表要用{ } 括起来,可指定@required注解标明该可选命名参数是必须要传值的:
const Scrollbar({Key key, @required Widget child})
Optional parameters
-
Optional parameters can be either named or positional, but not both.
-
将可选的函数参数用[ ]括起来,以此表示括号中的参数是可选的:
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
- 给可选参数赋初始值时,必须要是编译时常量,集合前要用const
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
cascades级联操作符
- cascades级联操作符以… 表示,可以在一个对象的成员上进行多次操作:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
Dart中的函数是一等公民(变量也是可以直接在一个文件中直接定义)
- 可以将函数作为参数传入方法中,或者赋值给一个变量
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
//将一个函数赋值给一个变量
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
匿名函数
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
如果匿名函数的参数只有一个,可以使用=>代替大括号{ },如:
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
- 将函数作为返回值
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}