Flutter之Dart语言基础

Dart语言的诞生

2011年10月,Google 发布了一种新的编程语言 Dart,谷歌希望利用这款语言,帮助程序开发者克服JavaScript语言的缺点,并使Dart支持所有项目,从小型松散的项目到Gmail和谷歌文档这种大型复杂的项目。Dart 语言可以说是集百家之长,拥有其他优秀编程语言的诸多特性和影子,另外,最重要的是,Dart成为了Flutter的官方开发语言~

Dart的特性

编译模式:JIT和AOT

我们都知道,程序在运行之前通常都需要编译,JIT和AOT是最常用的两种编译方式

  • JIT:即时编译,在开发时使用,可以动态下发和执行代码,开发测试效率高,但运行速度和性能会收到影响;
  • AOT:预先编译(静态编译),可以生成被直接执行的二进制代码,运行速度快、执行性能表现好,但每次执行前都需要提前编译,开发测试效率低;
    总结:JIT适合在开发测试时使用,AOT适合在发布时使用,而Dart是少数同时支持JIT和AOT的语言,Flutter非常受欢迎的功能热重载正是基于JIT,因此Dart 具有运行速度快、执行性能好的特点。
单线程模式

我们都知道,支持并发执行线程的高级语言(C++,Java等),都是以抢占式的方式切换线程,每个线程都会被分配一个固定的时间片来执行,这样当多线程操作更新共享资源时,就可能导致数据不同步的问题,虽然可以加锁来保证同步,但是锁本身会带来性能消耗,并且还可能出现死锁等比较严重的问题;这时候Dart单线程模式的优势就体现出来了,他不会存在资源竞争和数据同步的问题,一旦某个函数开始执行,直到这个函数执行完成,都不会被其他Dart代码打断;

基础语法和类型变量

变量和类型

在Dart中用var或具体类型来声明一个变量,用var声明表示类型是由编译器推断决定,或者你可以用具体类型来声明如:int x=0; 显式的告诉编译器你定义的变量类型;
默认情况下未初始化的变量值都是null,Dart是类型安全语言,所有类型都是对象类型(Object),一切变量的值都是类的实例;
Dart 内置了一些基本类型,如 num、bool、String、List 和 Map;
num:有两个子类int(整形)和double(浮点型)

int x = 10;
double y = 1.5;

bool类型,只有两个对象具有bool类型:true和false,他们都是编译时常量;
String由UTF-16的字符串组成,字符串变量既可以用单引号也可以用双引号表示,还可以在字符串中嵌入变量或表达式;可以用${express}的方式,将表达式放入字符串中,如果是一个标识符,可以省略{}

  var text = 'monkey';
  var text1 = 'this is :$text';
  var text2 = 'this is :${text.toUpperCase()}';
List和Map

就是我们常见的集合或数组和字典类型,在Dart中统称为集合类型,我们用个例子来展示一下List和Map的使用

  var arr1 = ["one", "two", "three"];
  var arr2 = List.of([1, 2, 3]);

  var map1 = {"name": "jiao", "sex": "male"};
  var map2 = new Map();
  map2['name'] = 'jiao';
  map2['sex'] = 'male';

容器里的元素有类型,比如arr2的类型是List<int>,map2则为Map<String,String>,Dart会自动根据上下文来推断;
和Java类似,在初始化集合对象时,我们可以为集合添加类型约束(泛型)如:

  var arr1 = <String>["one", "two", "three"];
  var arr2 = List<int>.of([1, 2, 3]);

  var map1 = <String, String>{"name": "jiao", "sex": "male"};
  var map2 = new Map<String, String>();

这样是不是更清晰~

常量

Dart中常量的定义可以用const和final关键字来声明
const:表示在编译期就能确定的值
final:表示在运行时可以确定的值
两者区别
const i = 1 (正确) const i =x+y(错误)
const必须直接赋一个字面量,而不能是一个变量或者表达式;
final i =1;(正确) final i =x+y(正确)
final则无以上限制,但是final的值一旦确定,就不能更改了;

函数

函数定义

Dart中所有的类型都是对象类型,函数也是对象,类型是function,这说明他可以定义为变量,甚至可以定义为参数传递给另一个函数;

  bool isZero(int num) {
    return num == 0;
  }

  void printInfo(int num, Function check) {
    print('$num is Zero:${check(num)}');
  }

  Function f = isZero;
  int x = 10;
  int y = 0;
  printInfo(x, f); // 输出 10 is Zero: false
  printInfo(y, f); // 输出 0 is Zero: true

首先定义了一个判断是否为0的函数isZero,然后定义了一个打印判断结果的函数printInfo,可以看到第二个函数的入参为第一个函数;
如果函数体只有一行表达式,可以像JavaScript那样用箭头函数来简化这个函数

  bool isZero(int num) => num == 0;

  printInfo(int num, Function check) => print('$num is Zero:${check(num)}');
函数可变参数

我们知道在C++或者Java中,函数支持重载,即提供同名但参数不同的函数,但在Dart中并不支持重载,但Dart提供了可选命名参数和可选参数;

  • {} 可选命名参数,以name:value 的方式指定参数;
  • [] 可选参数 ,意味着这些参数可以忽略;
  //{}设置可选命名参数
  addValue({int x, int y}) {
    print("x=$x,y=$y");
  }

  addValue(x: 10, y: 20);
  addValue(x: 10); //y可选 默认null
  addValue(y: 20); //x可选 默认null

  //{}可选命名参数设置默认值
  addValue1({int x, int y = 1}) {
    print("x=$x,y=$y");
  }

  addValue1(x: 10); //y可选 已设默认值1

  //[]可选参数
  printValue(bool x, [bool y]) {
    print("x=$x,y=$y");
  }

  printValue(true); //y可忽略 默认null
  printValue(true, false);

  //[]可选参数 默认值
  printValue1(bool x, [bool y = true]) {
    print("x=$x,y=$y");
  }

  printValue1(true); //y可忽略 已设默认值 true

通过上面的示例代码可以看出,既然都是可选参数,两者有什么区别呢?主要有两点区别:
1.{}访问是以 name:value的形式 []则不是
2.{}无需按参数顺序写参数 []则严格按照参数顺序写入参数

Dart是面向对象的语言,每个对象都是类的一个实例,都继承自顶层的Object,Dart中并没有public,protected,privite这些关键字,在声明变量和方法是加上""表示private,如果不加"",则默认是public的,这里要注意"_"的限制级别是库级别的,而不是类级别;

class Apple {
  num x, y;
  static num z = 0;

  //语法糖,等同于在函数体内:this.x = x;this.y = y;
  Apple(this.x, this.y);

  void printXY() => print("x=$x,y=$y");

  static void printZ() => print("z=$z");
}

在Apple类中,定义了两个成员变量x和y,通过构造函数语法糖进行初始化,而类变量z在声明时就已经赋好了默认值。
类的构造方法也可以使用可选命名参数和可选参数,另外Dart还支持命名构造函数 ,使类的实例化过程语义更清晰。

class Apple {
  num x, y, z;

  Apple(this.x, this.y) : z = 0;//初始化变量z

  Apple.start(num x) : this(x, 0);//重定向构造函数 调用上面的构造方法

  void printXYZ() => print("x=$x,y=$y,z=$z");
}

Apple类中有两个构造函数Apple和Apple.start,Apple.start将其成员变量初始化重定向到了Apple中,而Apple在初始化时为z赋上了默认值0

复用

在其他面向对象的语言中,我们要想复用其他类的变量和方法通常有两种方式继承和接口实现,在Dart中同样也可以:
继承: 继承自父类,子类由父类派生,会自动获得父类的方法和变量,子类也可以根据需要复写父类的构造函数或方法;
接口: 接口实现的话,子类主要获取到的是父类的方法或变量符号,需要自己实现父类的方法和变量,更多的是父类对子类进行约束;
下面,我们看一下在Dart中继承和接口的区别

class Apple {
  num x, y;
  void printValue() => print("x=$x,y=$y");
}

class Apple1 extends Apple {
  num z;
  @override//复写 printValue方法
  void printValue() => print("x=$x,y=#y,z=$z");
}

class Apple2 implements Apple{
  //成员变量需要重新声明
  @override
  num x;

  @override
  num y;

  @override
  void printValue() {
    //成员函数需要重新实现
    // TODO: implement printValue
  }

}

可以看到,继承的话和其他语言都差不多,Apple2是可以采用接口的方式(implements)实现一个类的,然而得到的仅仅是父类的一个空壳子,从语义层面可以当作Apple来用,父类中所有的成员变量和方法都需要重新实现;那有没有什么机制,我们是以非继承的形式实现一个类,并且能复用父类的方法和变量而无需重新声明?答案是肯定的,在Dart中有一个概念Mixin,即混入关键字with修饰,可以实现上述功能,可以被看成是具有实现方法的接口,说白了就是和继承一样的功能,但又不是继承;可以理解为为了解决多继承而出现的一种新的类之间关系。

class Apple1 extends Apple {
  num z;

  @override //复写 printValue方法
  void printValue() => print("x=$x,y=#y,z=$z");
}

class Apple2 with Apple {
  num z;

  @override //复写 printValue方法
  void printValue() => print("x=$x,y=#y,z=$z");
}

看,是不是和继承一模一样的作用

运算符

Dart和其他大多数语言一样,运算符基本作用都是一致的,我们这里只特殊说明几个比较常用但又并是其他语言都有的运算符,类似kotlin中的非空判断

  • ?. 如:apple?.printValue(); 这个比较好理解,当apple不为空时,执行printValue方法;
  • ??= 如:a??=value,如果a为null 赋给a的值为value,否则跳过;
  • ?? 如:我们在java中经常使用的 a!=null?a:b;如果a不等于null返回a的值,否则返回b,在Dart中我们可以直接使用:a??b;
    在Dart中一切皆对象,包括运算符也是对象成员函数的一部分
    Dart提供了类似C++的运算符复写机制,我们可以复写或自定义运算符;
class Apple {
  num x;

  Apple(this.x);

  num operator +(Apple a) => this.x + a.x * 5;
}

  Apple a1 = new Apple(10);
  Apple a2 = new Apple(20);

  print("a1+a2=${a1 + a2}");

输出结果:a1+a2=110
我们来分析一下:Apple类重写了运算符+,当Apple类进行+号运算时,如上例:a1+a2,首先取a1的x值10+a2的x值20乘以5 返回,所以最后得出的结果是110

总结

最后我们来总结一下以上内容

  • Dart语言的诞生,并了解了Dart语言的一些特性,编译模式,单线程模式等;
  • Dart语言的基础语法以及变量类型,List和Map的使用等;
  • 函数的定义,函数的可变参数,可选命名参数和可选参数以及两者的区别;
  • Dart中的类,类的复用的方式,及“混入”概念的理解;
  • Dart中的运算符,主要是非空判断的一些运算符使用,以及如何复写运算符;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Flutter日渐火爆,因此在进行Flutter学习前先学习一些其所使用的开发语言dart的基础,这篇文章主要学习...
    Samlss阅读 10,886评论 2 28
  • 此文章是v1.0+时编写,年代久远,小心有毒,谨慎食用!!! 一些重要概念 所有的东西都是对象,所有的对象都是类的...
    soojade阅读 10,041评论 2 27
  • Dart语法基础 Dart语言简介 Dart是Google推出的一门编程语言,最初是希望取代Javascript运...
    张叔叔阅读 10,575评论 1 9
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,513评论 1 51
  • 2018年10月30日,这段时间觉得自己挺差的,好像很忙,但又不知道忙些什么,前天晚上的小组会,民政同学说他能感觉...
    若非晚秋阅读 141评论 0 0