Dart语言基础,看完这篇文章就够了(一)

Dart

文章内容是我学习时的点滴笔记,如有不好的地方,欢迎指出。

上一篇文章Flutter初探我们知道了Flutter是一个使用Dart语言开发的跨平台移动UI框架。Dart又是什么呢?Dart 是一种易于学习、易于扩展、并且可以部署到任何地方的应用编程语言。
那Flutter和Dart什么关系?Flutter为什么选用dart?Dart又有哪些优势?Dart...吧啦吧啦~~~

一脸懵逼

咳...咳...咳...大家查阅相关资料了解上述问题后可以悄悄告诉小老弟。好,名人不说暗话,下面让小老弟带各位大佬走进Dart语言世界。

1 变量

1.1 变量的声明

vardynamicObject

①未初始化变量声明

vardynamicObject若未初始化的变量的话,变量值是可以动态改变的,看下面示例

void main() {
  var data;
  data = 1;
  data = "data";
  
  dynamic data2;
  data2 = 1;
  data2 = "data2";
  
  Object data3; 
  data3 = 333;
  data3 = "data3";
}

②初始化变量声明

相同点:

都可以直接声明变量,看下面示例

  var d1 = 123; //d1类型被推断为int类型
  dynamic d2 = "123"; //d2类型被推断为字符串类型
  Object d3 = "1234";

不同点:

  1. var声明初始化后不可再改变类型,而dynamic和Object可以。

  2. dynamic 编译阶段不检查类型,而Object会在编译阶段会检查类型;

看下面示例

  var d1 = 123; //d1类型被推断为int类型
  d1 = 1234;
//  d1 = "1123";//报错

  dynamic d2 = "123"; //d2类型被推断为字符串类型
  d2 = 123; //可以
  
  Object d3 = 123; //d3类型被推断为int类型
  d3 = "123"; //可以

  dynamic d = "1234";
  Object o = "121";
  d.test();
//  o.test();//编译不过

1.2 默认值

①没有初始化的变量自动获取一个默认值为null

②一切皆对象!!!对象的默认值为null

1.3 final和const

共同点:

  1. 声明的类型可省略,看下面示例
final str = "str";      //final String str = "str"; String这个类型 可省略
const str2 = "str2";    //const String str2 = "str2";与final一样,String可省略
  1. 初始化后不能再赋值(这与java一样);
  2. 不能和var同时使用,看下面示例
final ~~var~~  f1 = "";    //报错 不可与var同时使用
const  ~~var~~  f2 = "";    //报错 不可与var同时使用

区别(需要注意的地方):

  1. 类级别常量,使用static const;以下图DateTime源码为例


    DateTime
  2. const可使用其他const 常量的值来初始化其值;看下面示例
  const a = 1;
  const b = 2;
  var c = 3;
  final d =4;
  const sum = a+b;//可以,正常运行
  const sum2 = a+c;//报错
  const sum3 = a+d;//报错
  1. 使用const赋值声明,const可省略;看下面示例
  const list1 = [];
  const list2 = const [];//const 可省略
  1. 可以更改非final、非const变量的值,即使曾经具有const值;看下面示例
 var list = const [1, 2, 3];
  list = [3,2,1];
  print(list);//输出结果为 [3,2,1]
  1. const导致的不可变性是可传递的;看下面示例
  final list1 = [1,2,3];
  list1[0] = 0;
  print(list1);//输出[0,2,3]
  const list2 = [1,2,3];
  list2[0] = 0;//运行报错,不可修改
   print(list2);//运行报错,list2不可修改
  1. 相同的const常量不会在内存中重复创建;看下面示例
const a = 1;
const b =1;
const c =2;
print(identical(a,b));//true
print(identical(a,c));//false
  1. const需要是编译时常量;
const dt = DateTime.now();//报错,const必须是编译时常量
final dt1 = DateTime.now();//可以,正常运行

2 内置类型

类型 解释 类型 解释
Numbers 数值 Sets 集合
Strings 字符串 Maps 集合
Booleans 布尔值 Runes 符号字符
Lists 列表(数组) Symbols 标识符

2.1 内置类型-num、int、double

  • int : 整数值;
  • double : 64-bit双精度浮点数;
  • int和double是num的子类;

2.2 内置类型-String

  1. Dart 字符串是 UTF-16 编码的字符序列,可以使用单引号或者双引号来创建字符串;
  2. 可以使用三个单引号或者双引号创建多行字符串对象;
  3. 可以使用 r 前缀创建”原始raw”字符串;看下面示例
String s1 = "123" 'abc' "okok";
String s2 = "123" + 'abc';
String s3 = '''ewrwerAeawrwer
  eee''';
String s4 = '''ewrwerAeawrwer\neee''';
String s5 = r'''ewrwerAeawrwer\neee''';
print(s1);
print(s2);
print(s3);
print(s4);
print(s5);

运行结果:


运行结果.png

既然尝试了String,那再试一下StringBuffer吧,示例如下

StringBuffer sb1 = StringBuffer();
StringBuffer sb2 = StringBuffer();
sb1.write("333");
sb1.write("aaa");
sb1.write("666");
sb2..write("333")..write("aaa")..writeAll(['6','6','6']);//..级联符,可链式调用里面方法
print(sb1);//333aaa666
print(sb2);//333aaa666

StringBuffer对象不用调用.toString()方法就可以输出打印,为啥呢?我们看一下print()内部是如何实现的呢?看下图,原来它打印是调用的对象的toString()方法。


print源码
  1. 可以在字符串中使用表达式: ${expression},如果表达式是一个标识符,可以省略 {},如果表达式的结果为一个对象,则 Dart 会调用对象的 toString() 函数来获取一个字符串;看下面示例
var a = 1;
var b = 2;
print("${a + b}"); //输出结果:3

2.3 内置类型-bool

  • 与java不同的是,bool对象未初始化的默认值是null;看下面示例
bool bo;
print(bo);//输出:null
if(bo){//报错,因为bool未初始化默认值是null,所以这样调用运行时会报错
}

2.4 内置类型-List

Dart里的List和我们理解的List不太一样,它和Java中的 数组 有些类似。

  1. Dart中可以直接打印list包括list的元素,List也是对象。java中直接打印list结果是地址值。
  2. Dart中List的下标索引和java一样从0开始。
  3. 和java一样支持泛型。
  4. 有增删改查,支持倒序,自带排序、洗牌,可使用+将两个List合并。
  //声明
  //自动长度
  List growableList = List();
//  List growableList = new List()..length = 3;
  growableList..add(1)..add(2)..add('damon');
  print('growableList: ${growableList}');
  //固定长度
  var list = List(3); //List的声明,可以用var也可用List。
  list[0] = 1; //下标索引从0开始
  list[1] = 2;
  list[2] = 'damon';
  print('list: ${list}');
  //元素类型固定
  var typeList = List<int>();
  typeList.add(1);
  typeList.add(2);
  typeList.add(3);
  print('typeList: ${typeList}');
  //常用属性
  int first = typeList.first;
  print('typeList.first: ${first}'); //第一个元素
  int last = typeList.last;
  print('typeList.last: ${last}'); //最后一个元素
  int length = typeList.length;
  print('typeList.length: ${length}'); //元素个数
  bool isEmpty = typeList.isEmpty;
  print('typeList.isEmpty: ${isEmpty}'); //是否为空
  bool isNotEmpty = typeList.isNotEmpty;
  print('typeList.isNotEmpty: ${isNotEmpty}'); //是否不为空
  Iterable reversed = typeList.reversed;
  print('typeList.reversed: ${reversed}'); //倒序
  //常用方法 增删改查,排序,洗牌,复制子列表
  var list4 = [];
  //增
  list4.add(1);
  print('add 1 :${list4}');
  list4.addAll([2, 3, 4]);
  print('addAll [2, 3, 4] :${list4}');
  list4.insert(0, 0);
  print('insert(0, 0) :${list4}');
  list4.insertAll(1, [5, 6, 7]);
  print('insertAll(1, [5, 6, 7]) :${list4}');
  //删
  list4.remove(5);
  print('remove 5 :${list4}');
  list4.removeAt(2);
  print('remove at 0 :${list4}');
  //改
  list4[4] = 5;
  print('update list4[4] to 5 :$list4}');
  //range
  list4.fillRange(0, 3, 9);
  print('fillRange update list4[0]-list4[2] to 9 :$list4}');
  Iterable getRange = list4.getRange(0, 3);
  print('getRange list4[0]-list4[2] :$getRange}');
  //查
  var contains = list4.contains(5);
  print('list4 contains 5 :${contains}');
  var indexOf = list4.indexOf(1);
  print('list4 indexOf 1 :${indexOf}');
  int indexWhere = list4.indexWhere((test) => test == 5);
  print('list4 indexWhere 5 :${indexWhere}');
  //排序
  list4.sort();
  print('list4 sort :${list4}');
  //洗牌
  list4.shuffle();
  print('list4 shuffle :${list4}');
  //复制子列表
  var list5 = list4.sublist(1);
  print('sublist(1) list5 :${list5}');
  //操作符
  var list6 = [8, 9];
  print('list6 :${list6}');
  var list7 = list5 + list6;
  print('list5 + list6 :${list7}');

看下图,这是List有一些常用的属性,我们用的时候就知道,这里就不一一举例说明了。


List

2.5 内置类型-Map

 //声明
  //动态类型
  var dynamicMap = Map();
  dynamicMap['name'] = 'dongnao';
  dynamicMap[1] = 'android';
  print('dynamicMap :${dynamicMap}');
  //强类型
  var map = Map<int, String>();
  map[1] = 'android';
  map[2] = 'flutter';
  print('map :${map}');
  //也可以这样声明
  var map1 = {'name': 'dongnao', 1: 'android'};
  map1.addAll({'name':'damon'});
  print('map1 :${map1}');
  //常用属性
//  print(map.isEmpty); //是否为空
//  print(map.isNotEmpty); //是否不为空
//  print(map.length); //键值对个数
//  print(map.keys); //key 集合
//  print(map.values); //value集合

Map和Java类似,键值对,我们用的时候就知道,这里也就不一一举例说明了。

2.6 内置类型-Set无重复列表

 var dynamicSet = Set();
  dynamicSet.add('dongnao');
  dynamicSet.add('flutter');
  dynamicSet.add(1);
  dynamicSet.add(1);
  print('dynamicSet :${dynamicSet}');
  //常用属性与list类似

Set的基本用法也是和Java类似,但有几点和Java不太一样的地方。

  1. set1.difference(set2):返回set1集合里有但set2里没有的元素集合;
  2. set1.intersection(set2):返回set1和set2的交集;
  3. set1.union(set2):返回set1和set2的并集;
  4. set1.retainAll():set1只保留某些元素(要保留的元素要在原set中存在);

看下面示例:

  Set set1 = Set();
  set1.addAll(['a', 'b', 'a', 'c', 'd']);
  Set set2 = Set();
  set2.addAll(['a', 'b', 'a', 'e', 'f']);
//  print(set1.difference(set2));//补集,输出{c, d}
//  print(set1.intersection(set2));//交集,输出{a, b}
//  print(set1.union(set2));//并集,输出{a, b, c, d, e, f}
  set1.retainAll(['a', 'b']);//set1只保留某些元素(要保留的元素要在原set中存在)
  print(set1);//输出{a, b}

2.7 内置类型-Runes

Dart 中 Runes 是UTF-32字符集的String 对象。

  1. Runes用于在字符串中表示Unicode字符;
  2. 使用String.fromCharCodes显示字符图形;
  3. 如果非4个数值,需要把编码值放到大括号中;

看下面示例

Runes runes = new Runes('\u6787 \u2665  \u{1f605}  \u{1f60e}  \u{1f44d}');
print(String.fromCharCodes(runes));//输出:枇 ♥  😅  😎  👍

输出结果:

Runnes

CopyChar|免费特殊符号大全,可以玩一下。

2.8 内置类型-Symbol

  1. symbol字面量是编译时常量,在标识符前面加#;看下面示例
#foo_lib
#runtimeType
  1. 如果是动态确定,则使用Symbol构造函数,通过new来实例化;看下面实例
Symbol obj = new Symbol('name');  

Symbol标识符,主要是反射用,现在mirrors模块已经被移除(所以用不了反射了),所以了解一下就可以。

3 函数

3.1 函数定义

  1. Dart中函数是Function类型的对象;
  2. 所有的函数都有返回值。如果没有指定返回值,则默认把语句 return null; 作为函数的最后一个语句执行;
  3. 定义函数时可省略类型(不建议);看下面示例
/**
* 类型未省略类型
*/
  int add2(int a, int b) {
    return a + b;
  }

/**
 1. 参数类型和方法返回类型均省略(不建议省略)
*/
add(a,b){
    return a+b;
  }
  1. 对于只有一个表达式的方法,你可以选择 使用缩写语法=>表达式来定义(Kotlin是用=来实现),有点像Lambda;看下面实例
/**
 3. 未缩写
*/
  int add(int a, int b) {
    return a + b;
  }
  
/**
 4. 缩写
*/
  int add(int a, int b) =>a+b;
  1. 可在函数内部定义函数,支持嵌套;看下面实例
 add1() {
    int add2(int a, int b) => a + b;
  }

3.2 可选参数

  1. 可选命名参数:使用 {param1, param2, …} 的形式来指定命名参数。
  int add({int x, int y, int z}) {
    x ??= 1;
    y ??= 2;
    z ??= 3;
    return x + y + z;
  }

  print(add());
  print(add(x : 1, y : 2));
  print(add(x : 1, y : 2, z : 0));
  print(add3(z : 1, y : 2));
  1. 可选位置参数:把可选参数放到 [] 中,必填参数要放在可选参数前面。
  int add4(int x, [int y, int z]) {
    y ??= 2;
    z ??= 3;
    return x + y + z;
  }
  print(add4(1));
  print(add4(1, 3));
  print(add4(1, 6, 6));
  1. 可选命名参数默认值(默认值必须是编译时常量),可以使用等号‘=’或冒号’:‘。(Dart SDK 1.21 之前只能用冒号,冒号的支持以后会移除,所以建议使用等号)
 int add5(int x, {int y = 2, int z = 3}) {
    return x + y + z;
  }
    //前面的必填参数没有名字
  print(add5(1, y: 10, z: 2));
  1. 可选位置参数默认值(默认值必须是编译时常量),只能使用等号'='。
 int add6(int x, [int y = 2, int z = 3]) {
    return x + y + z;
  }

  print(add6(1));
  1. 可使用list或map作为默认值,但必须是const。
  void func(
      {List list = const [1, 2, 3],
      Map map = const {1: 1, 'name': 'dongnao'}}) {
    //TODO ...
  }

3.3 匿名函数

  1. 无参匿名
  var printFunc = () => print("666");
  printFunc();
  
  //语法上也支持这样调用,但不建议
  (() => print("666"))();
  1. 有参匿名
  var printFunc1 = (name) => print("$name");
  printFunc1('秃头老王');
  1. 匿名函数传参
 List test(List ls, String fun(str)) {
    for (int i = 0; i < ls.length; i++) {
      ls[i] = fun(ls[i]);
    }
    return ls;
  }
  List ls = ['a', 'b', 'c'];
  print( test(ls, (str) => str * 2));

输出结果:[aa, bb, cc]
我们看一下List的forEach源码:

forEach

其实是循环调用传入的f(element)方法,看下面实例:

List ls = ['a', 'b', 'c'];
ls.forEach((ele) => print(ele));

输出结果:


运行结果
  1. 闭包(返回Function对象)
  Function makeAddFun(int a) {
    a++;
    return (int b)=>a+b;
  }

  print(makeAddFun(1)(2));//相当于: var f = makeAddFun(1);     print(f(2));

输出结果:4

  1. 函数别名
void main(){
  MyFunc myFunc = subtsract(2, 1);
  myFunc = add(2, 2);
  myFunc = divide(4, 2);
  calculator(2, 1, subtsract);
}

typedef MyFunc(int a, int b);
//根据MyFunc相同的函数签名定义两个函数
add(int a, int b) {
  print('add:${a + b}');
}

subtsract(int a, int b) {
  print('subtsract: ${a - b}');
}

divide(int a, int b) {
  print('divide: ${a / b}');
}

输出结果:


输出结果

4 操作符

操作符

4.1 后缀操作符 ?.

条件成员访问 和 . 类似,但是左边的操作对象不能为 null,例如 foo?.bar 如果 foo 为 null 则返回 null,否则返回 bar 成员

String a;
print(a?.length);

输出结果:null

4.2 取商操作符 ~/

被除数 ÷ 除数 = 商 ... 余数,A ~/ B = C,这个C就是商。相当于Java里的 /

  print(2 / 3);     //输出结果:0.6666666666666666
  print(2 ~/ 3);    //输出结果:0

4.3 类型判定操作符

类型判定操作符:asisis!在运行时判定对象类型

//as 类型转换
  num iNum = 1;
  num dNum = 1.0;
  int i = iNum as int;
  double d = dNum as double;
  print([i, d]);

//  String s = iNum as String; //不能转换,报错

  //is 如果对象是指定的类型返回 True
  print(iNum is int);
  Child child;
  Child child1 = new Child();
  print(child is Parent); //child is Null
  print(child1 is Parent);

  //is! 如果对象是指定的类型返回 False
  print(iNum is! int);

4.4条件表达式

  bool isFinish = true;
  String txtVal = isFinish ? 'yes' : 'no';
  // expr1 ?? expr2,如果 expr1 是 non-null,返回其值; 否则执行 expr2 并返回其结果。
  bool isPaused;
  isPaused = isPaused ?? false;
  //或者
  isPaused ??= false;

4.5级联操作符

..可以在同一个对象上 连续调用多个函数以及访问成员变量。
严格来说, 两个点的级联语法不是一个操作符。 只是一个 Dart 特殊语法。

  StringBuffer sb = new StringBuffer();
  sb
    ..write('dongnao')
    ..write('flutter')
    ..write('\n')
    ..writeln('damon');
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266