一,定义变量
1,明确声明变量
明确声明变量格式:
变量类型 变量名称 = 赋值;
定义的变量可以对其值进行修改,但是仅限于相同类型的值。
String name = '字符串';
int age = 18;
double height = 1.88;
print("$name, $age, $height");
2,类型推导变量
类型推导
类型推导变量格式:
var/dynamic/const/final 变量名称 = 赋值;
var
var声明变量,会对针对赋值的类型,自动推导出变量的类型,可以用runtimeType来或取变量的类型。
var a;
var b = 3;
var c = 1.88;
var d = 'String';
var e = [1,2,3];
print(a.runtimeType); // Null
print(b.runtimeType); // int
print(c.runtimeType); // double
print(d.runtimeType); // String
print(e.runtimeType); // List<int>
var声明的变量赋值后类型就已经确定,不能够在赋值其他类型的值:
var a = 1;
a = 1.88; // 报错:A value of type 'double' can't be assigned to a variable of type 'int'.
dynamic
dynamic声明的变量,会对针对赋值的类型,自动推导出变量的类型,并且可以赋值其他类型的值:
dynamic a = 1;
print(a.runtimeType); // int
a = 'abc';
print(a.runtimeType); // String
final&const
final和const都是用于定义常量,定义之后的值不能够修改:
final a = "Jack";
a = "Rose"; // 报错
const b = 3.14;
b = 123; // 报错
final和const区别
- final在赋值时,可以动态获取,如赋值一个函数的结果。
- const在赋值时,赋值的值必须在编译期间就确定下来。
double getPi() {
return 3.14;
}
main(List<String> args) {
final pi1 = getPi();
const pi2 = 3.14;
const pi3 = getPi(); // 报错
}
二,数据类型
1,数字类型
数值型可以用 num,整数用 int,浮点数用 double,int 和 double 继承自 num。
int age = 18;
int hexAge = 0x12;
print(age);
print(hexAge);
double height = 1.88;
print(height);
num 可以赋值 int 和 double
num a = 3;
print(a.runtimeType); // int
a = 3.14;
print(a.runtimeType); // double
double 转 int
double double1 = 1.4;
double double2 = 1.6;
int a = double2.toInt(); // 转换成int,相当于floor
int b = double1.round(); // 转换成int,四舍五入
int c = double1.ceil(); // 转换成int,向上取整
int d = double2.floor(); // 转换成int,向下取整
print("$a ${a.runtimeType}"); // 1, int
print("$b ${b.runtimeType}"); // 1, int
print("$c ${c.runtimeType}"); // 2, int
print("$d ${d.runtimeType}"); // 1, int
int 转 double
int i = 1;
double a = i.toDouble();
print("$a, ${a.runtimeType}"); // 1.0,double
String 转 num
num a = int.parse('1');
num b = double.parse('3.14');
// num c = int.parse('3.14'); // 报错,不可以浮点数字符串转int
num d = double.parse('3');
print("$a ${a.runtimeType}"); // 1 int
print("$b ${b.runtimeType}"); // 3.14 double
// print("$c ${c.runtimeType}");
print("$d ${d.runtimeType}"); // 3.0 double
num 转 String
String str1 = 1.toString(); // 1 String
String str2 = 1.4.toString(); // 1.4 String
String str3 = 3.1415926.toStringAsFixed(2); // 3.14 String
print("$str1 ${str1.runtimeType}");
print("$str2 ${str2.runtimeType}");
print("$str3 ${str3.runtimeType}");
2,布尔类型
bool,取值为 true 或 false,dart中不能非0即真,或非空即真。
var result = 3 > 4;
print("$result ${result.runtimeType}"); // false bool
3,字符串类型
Dart字符串是UTF-16编码单元的序列,可以使用单引号或双引号创建一个字符串:
var str1 = 'str1'; // 单引号创建字符串
var str2 = "str2"; // 双引号创建字符串
String str3 = "str\n3"; // \n 可以换行
// 可以用 ''' 创建多行字符串,每一行前面的空格是有效占位的
String str4 = '''000
123
456
''';
print(str1); // str1
print(str2); // str2
/**
* str
* 3
*/
print(str3);
/**
* 000
* 123
* 456
*/
print(str4);
字符串拼接:
var str1 = '123';
var str2 = 'abc';
var str3 = str1 + "+" + str2;
var str4 = "$str1+$str2";
print(str3); // 123+abc
print(str4); // 123+abc
4,集合类型
Dart内置了最常用的三种集合类型:List、Set、Map。
1,List
List是一个有序的集合类型,与数组相似,并且支持泛型。
List的定义:
// 类型推导定义:如果数组中都是一个类型,泛型推导为对应的类型
var list1 = ['a', 'b', 'c'];
// 类型推导定义:如果数组中不是一个类型,泛型推导为Object
var list2 = [1, 'b', 'c'];
// 指定类型定义,如果不写泛型,默认泛型为dynamic
List list3 = [1, 2, 3];
// 指定类型定义,并写明泛型类型
List<int> list4 = [4, 5, 6];
// 类型推导定义一个空List,泛型默认为dynamic
var list5 = [];
print("$list5, ${list5.runtimeType}");
// 指定类型定义一个空List,泛型默认为dynamic
List list6 = [];
print("$list6, ${list6.runtimeType}");
// 类型推导定义一个空List,指定泛型类型
var list7 = <int>[];
print("$list7, ${list7.runtimeType}");
// 指定类型定义一个空List,指定泛型类型
List<int> list8 = [];
print("$list8, ${list8.runtimeType}");
关于泛型需要注意的是,通过var 类型推导创建,如果有初始值并且初始值都是同一类型,泛型类型会自动为该类型。而通过指定类型创建,如果没有显示值明泛型类型,泛型默认为dynamic,无论是否有初始值。
上面Object和dynamic都是可以指定任意类型,区别在于Object类型编译时会进行语法检查,该类型只能够调用Object类型的方法,否则会显示语法错误。dynamic则不会进行语法检查,运行时如果调用不属于该类型的方法,会抛出运行时错误。
List常用的操作:
List<int> list = [1, 2, 3];
// 集合长度: 3
var listLength = list.length;
// for in 遍历: 1,2,3
for (int i in list) {
print(i);
}
// forEach 遍历
list.forEach((element) => print(element));
// 尾部添加元素: [1, 2, 3] 尾部添加4 [1, 2, 3, 4]
list.add(4);
// 插入元素: [1, 2, 3, 4] index为0位置插入0 [0, 1, 2, 3, 4]
list.insert(0, 0);
// 移除尾部元素: [0, 1, 2, 3, 4] 移除尾部元素 [0, 1, 2, 3]
list.removeLast();
// 移除指定位置元素: [0, 1, 2, 3] 移除index为0位置的元素 [1, 2, 3]
list.removeAt(0);
// 移除元素 [1, 2, 3] 移除元素3 [1, 2]
list.remove(3);
// 是否包含元素 [1, 2]包含2,返回true
bool contains2 = list.contains(2);
// 移除指定区间的元素,从start位置开始,移除移除end - start个元素,如果end = start,则不移除任何元素
// [1, 2] 从index为0开始,移除(1-0)= 1个元素 [2]
list.removeRange(0, 1);
// 批量添加元素 [2] 添加 [3,4,5] [2, 3, 4, 5]
list.addAll([3, 4, 5]);
// 通过条件移除元素 [2, 3, 4, 5] 移除能被2整除的元素 [3, 5]
list.removeWhere((element) => element % 2 == 0);
list = [1,2,2,3];
// 返回指定元素在List中的第一个下标,[1, 2, 2, 3]中第一个2的index 返回 1
print(list.indexOf(2));
// 返回指定元素在List中的最后一个下标, [1, 2, 2, 3]中最后一个2的index 返回 2
print(list.lastIndexOf(2));
// 如果不存在返回-1, [1, 2, 2, 3] 不包含 0,返回 -1
print(list.indexOf(0));
// 返回满足条件的第一个元素, [1, 2, 2, 3] 返回第一个不被2整除的元素下标,返回0
print(list.indexWhere((element) => element % 2 != 0));
// 返回满足条件的最后一个元素,[1, 2, 2, 3] 返回最后一个不被2整除的元素下标,返回3
print(list.lastIndexWhere((element) => element % 2 != 0));
部分函数调用的参数使用了匿名函数,比如:list.indexWhere((element) => element % 2 != 0),这里传入的参数是一个函数,具体语法这里不展开,后面关于函数的笔记详细记录。
2,Set
Set类似于其他语言的集合类,它是无序并且不重复的集合,和List一样支持泛型。
Set的定义
// 类型推导定义 如果初始值都是同一类型,泛型为该类型 int
// 如果初始值有重复元素,会自动去除重复元素
var set1 = {1, 2, 2, 3};
print("$set1 Type: ${set1.runtimeType}");
// 类型推导定义 如果初始值类型不同,泛型为 Object
var set2 = {1, 2, '3'};
print("$set2 Type: ${set2.runtimeType}");
// 指定类型定义,如果没有写明泛型类型,默认为 dynamic
Set set3 = {1, 2, 3};
print("$set3 Type: ${set3.runtimeType}");
// 指定类型定义,并且指明泛型类型
Set<int> set4 = {1, 2, 3};
print("$set4 Type: ${set4.runtimeType}");
// 类型推导方式想定义一个空元素的Set,需要指定一个泛型,直接 {} 默认初始化类型为Map<dynamic, dynamic>
var set5 = <int>{};
print("$set5 Type: ${set5.runtimeType}");
// 指定类型初始化一个空元素的Set,泛型默认为dynamic
Set set6 = {};
print("$set6 Type: ${set6.runtimeType}");
// 指定类型初始化一个空元素的Set,同时指定泛型类型
Set<int> set7 = {};
print("$set7 Type: ${set7.runtimeType}");
关于泛型需要注意的是,通过var 类型推导创建,如果有初始值并且初始值都是同一类型,泛型类型会自动为该类型。而通过指定类型创建,如果没有显示值明泛型类型,泛型默认为dynamic,无论是否有初始值。
如果打印Set的runtimeType会发现,类型并不是Set类型:
Set<int> set1 = {1,2,3};
print(set1.runtimeType); // _CompactLinkedHashSet<int>
这是因为Set是一个抽象类,其内部通过工厂方法调用其子类LinkedHashSet的初始化方法,LinkedHashSet也是一个抽象类,调用其工厂方法,返回实际的对象,它的工厂方法通过external关键字在其他的地方实现,这里就先不展开,后面会在对象初始化的笔记中详细记录。
// Set
abstract class Set<E> extends EfficientLengthIterable<E> {
factory Set() = LinkedHashSet<E>;
...
// LinkedHashSet
abstract class LinkedHashSet<E> implements Set<E> {
external factory LinkedHashSet(
{bool equals(E e1, E e2),
int hashCode(E e),
bool isValidKey(potentialKey)});
...
Set常用操作这里也不记录了,大概的语法和和List很多都一样,只是多了些集合之间的交集并集等。
3,Map
Map通过Key和Value存储数据,和其他语言的Map或Objective-C的字典非常相近,本质原理上是一个哈希表。
关于Map的初始化、常用方法其它语言非常类型,并且和Set\List的函数类型基本一致,这里不重复记录。