关于dart的数据类型和数据值
- dart支持数据类型定义,但不强制要求进行数据类型定义,能自行推导数据类型
- dart中一切值都是对象
var, const, final
- dart建议局部变量通过var定义,var表示可改变值的变量
- final 和 const 都表示值不可改的变量
- const 变量的变量值在编译时就得确定, 只能初始化一次,且在定义时就得初始化,不可以用可变变量对其进行初始化,后续完全不可改
- final 变量定义时可以不被初始化,但只能初始化一次,可以用可变变量对其进行初始化,可变变量改变,不影响final变量,后续不可改
- 当一个函数调用被const修饰,那么该函数入参应该都是常量,若参数也为函数调用,那么函数参数的参数也应该是常量。否则就会出现标题中的错误。解决方式,可以将const移除掉
String name = '张三';
// 这里会报错,因为name是值可变变量, const要求变量值在编译时就得确定,但根据语法name的值是可变的,会导致tmp值无法确定,因此报错
const String tmp = '姓名${name}';
print(tmp);
const String name = '张三';
// 这里不会报错, 因为name也是const, 索引tmp值在编译时,即可确定
const String tmp = '姓名${name}';
print(tmp);
const list = ['a'];
// 语法不会报错,但运行时会报错,因为const变量是完全不可改的变量,即使变量值是List类型
list.add('b');
print(list);
String name = '张三';
// 可以用可变变量对final变量进行初始化,后续可变变量的修改不会影响final变量
final String tmp = '姓名${name}';
print(tmp); // 输出: 姓名张三
name = '王五';
print(tmp); // 输出:姓名张三
String name = '张三';
// 只定义final变量,不进行初始化
final String tmp;
// 对final变量进行一次初始化. P.S. 只能进行一次初始化
tmp = '姓名${name}';
print(tmp);
// 这里会语法报错,因此 final 变量只能进行一次初始化
tmp = '你好'
final list = ['a'];
// 如果final变量的实际类型是List这类引用数据类型,那内容是可以改变的
list.add('b');
print(list);
关于数组
dart中和其他编程语言不同,没有直接的数组类型,只有List
基本数据类型
Number
又分两种子类型: int 和 double
int 和 double 之间无法相互转换,但都可以转换为num
var x = 1;
print(x.runtimeType);
// 这里语法会报错,因为int无法与double相互转换
double y = x;
print(y.runtimeType);
var x = 1;
print(x.runtimeType);
// 这里没问题,因为int和double都可以转换为num类型
num y = x;
print(y.runtimeType);
整数类型的数值,会自动识别为 int
var x = 1;
print(x.runtimeType); // 输出: int
小数类型的数值,会自动识别为 double
var x = 1.0;
print(x.runtimeType); // 输出: double
字符串转int
String str = '113';
int x = int.parse(str);
print(x); // 输出: 113
print(x.runtimeType); // 输出: int
字符串转double
String str = '113';
double x = double.parse(str);
print(x); // 输出: 113.0
print(x.runtimeType); // 输出: double
String
- Dart 字符串是一组 UTF-16 单元序列。 字符串通过单引号或者双引号创建。可以通过
${expression}方式内嵌表达式 - 可以通过
'''内容'''或"""内容"""创建多行文本
String str = '年龄:12';
print(str);
str = '张三,${str}';
print(str);
str = '''你好
这是多行文本
''';
print(str);
判断字符串是否为空
String str = '你好';
print(str.isEmpty); // 输出: false
str = '';
print(str.isEmpty); // 输出: true
Boolean
- dart只有true和false是布尔值
- if判断和assert只能使用布尔值,不能用非布尔值判断(这一点和其他编程语言有很大区别)
// 检查空字符串。
var fullName = '';
assert(fullName.isEmpty);
// 检查 0 值。
var hitPoints = 0;
assert(hitPoints <= 0);
// 检查 null 值。
var unicorn;
assert(unicorn == null);
// 检查 NaN 。
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
String str;
// 这里会语法报错, dart的if语句只能使用布尔值判断
if (str) {
print(1);
}
List
dart中没有直接意义上的数组,替代品是List
List<int> arr = [1, 3, 5];
print(arr);
print(arr.runtimeType); // 输出: List<int>
// 可通过类型数组下标的方式获取指定位置的值
print(arr[2]); // 输出: 5
// 可以通过下标方式赋值
arr[3] = 10;
// 获取长度
print(arr.length);
// 判断是否为空
print(arr.isEmpty);
Set
元素唯一且无序的集合
Set<int> arr = {3, 1, 5};
print(arr);
arr.forEach((int item) {
print(item);
});
print(arr.runtimeType); // 输出: _Set<int>
// 定义set集合
var arr = <int>{3, 1, 5};
print(arr);
arr.forEach((int item) {
print(item);
});
print(arr.runtimeType); // 输出: _Set<int>
// 定义一个空的set集合
var elements = <String>{};
elements.add('fluorine');
print(elements.runtimeType);// 输出: _Set<string>
是 Set 还是 Map ? Map 字面量语法同 Set 字面量语法非常相似。 因为先有的 Map 字母量语法,所以 {} 默认是 Map 类型。 如果忘记在 {} 上注释类型或赋值到一个未声明类型的变量上, 那么 Dart 会创建一个类型为 Map<dynamic, dynamic> 的对象。
Map
Map 是用来关联 keys 和 values 的对象。 keys 和 values 可以是任何类型的对象。在一个 Map 对象中一个 key 只能出现一次。 但是 value 可以出现多次。
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = { 2: 'helium', 10: 'neon', 18: 'argon', };
Map<String, dynamic> tmp = {'name': '张三', 'age': 12};
print(tmp);
print(tmp.runtimeType); // 输出: _Map<String, dynamic>
var tmp = {'name': '张三', 'age': 12};
print(tmp);
print(tmp.runtimeType); // 输出: _Map<String, Object>
是 Set 还是 Map ? Map 字面量语法同 Set 字面量语法非常相似。 因为先有的 Map 字母量语法,所以 {} 默认是 Map 类型。 如果忘记在 {} 上注释类型或赋值到一个未声明类型的变量上, 那么 Dart 会创建一个类型为 Map<dynamic, dynamic> 的对象。
Rune
在 Dart 中, Rune 用来表示字符串中的 UTF-32 编码字符。
Unicode 定义了一个全球的书写系统编码, 系统中使用的所有字母,数字和符号都对应唯一的数值编码。 由于 Dart 字符串是一系列 UTF-16 编码单元, 因此要在字符串中表示32位 Unicode 值需要特殊语法支持。
表示 Unicode 编码的常用方法是, \uXXXX, 这里 XXXX 是一个4位的16进制数。 例如,心形符号 (♥) 是 \u2665。 对于特殊的非 4 个数值的情况, 把编码值放到大括号中即可。 例如,emoji 的笑脸 (�) 是 \u{1f600}。
String 类有一些属性可以获得 rune 数据。 属性 codeUnitAt 和 codeUnit 返回16位编码数据。 属性 runes 获取字符串中的 Rune 。
下面是示例演示了 Rune 、 16-bit code units、 和 32-bit code points 之间的关系。
main() {
var clapping = '\u{1f44f}';
print(clapping);
print(clapping.codeUnits);
print(clapping.runes.toList());
Runes input = new Runes( '\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(new String.fromCharCodes(input));
}
Symbol
一个 Symbol 对象表示 Dart 程序中声明的运算符或者标识符。 你也许永远都不需要使用 Symbol ,但要按名称引用标识符的 API 时, Symbol 就非常有用了。 因为代码压缩后会改变标识符的名称,但不会改变标识符的符号。 通过字面量 Symbol ,也就是标识符前面添加一个 # 号,来获取标识符的 Symbol 。
#radix
#bar
运算符
流程控制
异常
函数
返回值
所有函数都会返回一个值。 如果没有明确指定返回值, 函数体会被隐式的添加 return null; 语句。
foo() {}
assert(foo() == null);
main() 函数
任何应用都必须有一个顶级 main() 函数,作为应用服务的入口。 main() 函数返回值为空,参数为一个可选的 List<String>。
void main() {
print('hello');
}
// 这样运行应用: dart args.dart 1 test
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}
匿名函数与命名函数
main() {
var list = ['apples', 'bananas', 'oranges'];
// forEach调用匿名函数
list.forEach((item) {
print('$item');
});
print('');
// forEach调用命名函数
list.forEach(fun);
}
void fun(String item) {
print('$item');
}
函数体只有一个返回语句的函数语法糖
main() {
var fun = (String name) => '姓名:$name';
print(fun('张三'));
}
命名参数与命名可选参数
void main() {
test(age: 22);
test2();
test2(str1: '张三', str2: '里斯');
test2(str1: '张三');
}
/**
* 使用命名参数,且age为必传, name如果不传则使用默认值
*/
void test({String name = '张三', required int age}) {
print('${name} ${age}岁');
}
/**
* 使用命名参数,且str1, str2都不是必填的
*/
void test2({String? str1, String? str2}) {
var str = StringBuffer();
print(str.runtimeType);
if (str1 != null) {
str.write(str1);
}
if (str2 != null) {
str.write(str2);
}
print(str.toString());
}
位置参数与位置可选参数
void main() {
test('张三');
test('里斯', 12);
test('王五', 21, false);
}
/**
* 使用命名参数,且age为必传, name如果不传则使用默认值
*/
void test(String name, [int? age, bool male = true]) {
var str = StringBuffer();
str.write(name);
if (male) {
str.write(' 性别: ${male ? '男' : '女'}');
}
if (age != null) {
str.write(' ${age}岁');
}
print(str);
}
main() {
// 这个调用会导致doStuff内部报错,因为list默认值被声明成了不可改的const类型
// doStuff();
// 这里不会报错,因为此时list是普通的List<int>
doStuff(list: [44]);
}
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print(list.runtimeType);
// list参数使用的是默认值,则修改这个list会报错,否则不会报错
list.add(233);
print('list: $list');
print('gifts: $gifts');
}