flutter前言-dart语言(一)

Dart语言是使用flutter框架开发时候必备的语言,flutter是一个跨平台的框架,一套代码就可以完美实现安卓和ios两个平台,适配也很不错,Dart语言很友好,和java很类似,学习成本不高,推荐学习。

接下来我会通过两篇文章,带大家一起进入Dart之旅。

目录(谁知道简书md自动生成目录方法留言教我,谢谢)

image.png

概念

  1. 万物皆对象,所有的对象都是类的实例,如 数字、函数、null
    等也都是对象,所有的对象都继承自 Object 类。
  2. 在 Dart 1.x 中,强类型 strong mode 是可选的,但在 Dart 2 中,默认就是 strong mode。
  3. Dart 支持顶级函数,也支持类或对象的静态和实例方法。也可以在函数内部嵌套函数或本地函数;同样支持顶级变量,也支持类或对象的静态变量和实例变量(也被称作字段或属性)
  4. Dart没有 public、protected、private等关键字,如果一个标识符以 _开头则表示私有
  5. 没有初始化的变量都会被赋予默认值null

类型:

numbers、strings、bool、list、map、runes、symbol

numbers : 数据类型
  • int 取值范围:-2^53 to 2^53
  • double
void _numbersDemo() {
  int intNum = 12;
  double doubleNum = 12.12;
  //发现 + 必须都是string类型的才可以,所以使用.toString()
  print("int = " + intNum.toString() + " doubule=" + doubleNum.toString());
}
运行结果:int = 12 doubule=12.12
strings : 字符串类型
  • Dart 的String 是 UTF-16 编码的一个队列
  • '...'、"..." 表示字符串
  • '''...'''、"""..."""表示多行字符串
  • r'...'、r"..."表示“raw”字符串
void _stringsDemo(){
  String string1 = 'rocker1';
  String string3 = '''rocker3_1
  rocker3_2
  rocker3_3''';
  String string5Origin = 'rocker56 \nrocker56';
  String string5 = r'rocker5 \n rocker5';
  print(string1);
  print(string3);
  print("********");
  print(string5Origin);
  print(string5);
}
运行结果:
rocker1
rocker3_1
  rocker3_2
  rocker3_3
********
rocker56 
rocker56
rocker5 \n rocker5
bool : 布尔类型

与java类似,Dart 是强 bool 类型检查,只有 bool 类型的值是true 才被认为是 true

List : 列表、数组

具有一系列相同类型的数据被称为 List 对象。
list 对象的第一个元素的位置是0,最后个元素的索引是list.lenght - 1。

void _listDemo(){
  var names = new List();
  //或者简单的用list来赋值
  //List<String> names =["jim","rocker"]
  //添加元素
  names.add("rocker");
  //添加多个元素
  names.addAll(["jim","tom","abc","wangxiaojian"]);
  //打印数组
  print("before names="+names.toString());
  //获取list长度
  print("length="+names.length.toString());
  //删除指定元素,成功返回true,失败返回false
  names.remove("jim");
  //删除最后一个元素,返回删除的元素 names.removeLast();
  //删除指定范围元素,含头不含尾,成功返回null names.removeRange(start,end);

  // 删除指定条件的元素,成功返回null
  names.removeWhere((item) => item.length >6);

  //sort()对元素进行排序,传入一个函数作为参数,return <0表示由小到大, >0表示由大到小
  names.sort((a, b) => a.compareTo(b));
  print("after names="+names.toString());
}
运行结果:
before names=[rocker, jim, tom, abc, wangxiaojian]
length=5
after names=[abc, rocker, tom]
map:字典

Map 类型将keys 和 values 关联在一起。
keys 和 values 可以是任意类型的对象。
像其它支持Map 的编程语言一样,Map 的 key 必须是唯一的。

void _mapDemo() {
  // Map的声明
  var person = {
    'wangxiaojian': ['15', "pingpang", 'other'],
    'xiaoming': ['16', 'basketball'],
    'aihua': ['15', 'football']
  };
  var person1 = new Map();
  //指定键值对的参数类型
  var dog = new Map<int, String>();
  //Map的赋值,中括号中是Key,这里可不是数组
  dog[54] = 'wangcai';
  print("before dog[54]=" + dog[54] );
  //Map中的键值对是唯一的,同Set不同,第二次输入的Key如果存在,Value会覆盖之前的数据
  dog[54] = 'tiedan';
  print("after dog[54]=" + dog[54] );
  //检索Map是否含有某Key
  print("does it include  dog[54]=" + dog.containsKey(54).toString() );
  //删除某个键值对
  dog.remove(54);
}
运行结果:
before dog[54]=wangcai
after dog[54]=tiedan
does it include  dog[54]=true
runes 类型

runes 是UTF-32字符集的string 对象。
codeUnitAt 和 codeUnit 用来获取UTF-16字符集的字符。
使用runes 来获取UTF-32字符集的字符。

void _testRunes(){
  var string = '\u{1f44f}';
  print(string);
  print(string.codeUnits);
  print(string.runes.toList());

  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(input.toList());
}
运行结果:
👏
[55357, 56399]
[128079]
[9829, 32, 32, 128517, 32, 32, 128526, 32, 32, 128123, 32, 32, 128406, 32, 32, 128077]
Symbol

symbol字面量是编译时常量,在标识符前面加#。如果是动态确定,则使用Symbol构造函数,通过new来实例化。
一般程序中不会使用Symbol类型。

流程控制语句

  • if...else
  • for
  • while do-whild
  • break continue
  • switch...case
  • assert(仅在checked模式有效)

函数(Functions)

函数都有返回值,如果没有指定函数返回值,则默认返回值是null,没有返回值的函数,系统会在最后添加隐式的return 语句。

函数可以有两种类型的参数:

  • 必须的:必须参数放在参数列表前面。
  • 可选的:可选参数放在必须参数后面。
可选参数

可以通过名字或位置指定可选参数,但是两个不能同时存在。

  • 命名可选参数使用{},默认值使用冒号:,调用时需指明参数名,与顺序无关。
void _testOptionParams(String name,{age:0,interest:null}){
  print("name="+name+" age="+age.toString()+" interest="+interest.toString());
}
void main() {
  _testOptionParams("wangxiaojian",age: 30,interest:"pingpang");
}
运行结果:
name=wangxiaojian age=30 interest=pingpang
  • 位置可选参数使用[],默认值使用等号=,调用时参数按顺序赋值。
void _testOptionParams(String name,[age=0,interest=null]){
  print("name="+name+" age="+age.toString()+" interest="+interest.toString());
}
void main() {
  _testOptionParams("wangxiaojian","pingpang");
}
运行结果:
name=wangxiaojian age=pingpang interest=null
操作符

is is!操作符判断对象是否为指定类型,如numbers、string等。
as用来类型断言。

异常

throw
  • 抛出固定类型的异常:
throw new FormatException('Expected at least 1 section');
  • 抛出任意类型的异常:
throw 'Out of llamas!';
  • 因为抛出异常属于表达式,可以将throw语句放在=>语句中,或者其它可以出现表达式的地方:
distanceTo(Point other) =>
    throw new UnimplementedError();
catch

将可能出现异常的代码放置到try语句中,使用catch来处理异常。
可以向catch()传递1个或2个参数。第一个参数表示:捕获的异常的具体信息,第二个参数表示:异常的堆栈跟踪(stack trace)。

void _testException({demo:100}){
  try{
    var i = 2/0;
    print(i.toString()+" "+demo);
  }catch(e,s){
    print('Exception details:\n $e');
    print('Stack trace:\n $s');
  }
}
void main() {
  _testException();
}
运行结果:
Exception details:
 type 'int' is not a subtype of type 'String'
Stack trace:
 #0      _testException (file:///Users/wangxiaojian/Documents/androidCode/flutter_rong_app/test/widget_test.dart:99:28)
#1      main (file:///Users/wangxiaojian/Documents/androidCode/flutter_rong_app/test/widget_test.dart:13:3)
#2      _rootRun (dart:async/zone.dart:1126:13)
#3      _CustomZone.run (dart:async/zone.dart:1023:19)
#4      runZoned (dart:async/zone.dart:1501:17)
#5      Declarer.declare (package:test/src/backend/declarer.dart:121:22)
#6      RemoteListener.start.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test/src/runner/remote_listener.dart:118:26)
......
rethrow、finally

rethrow语句用来处理一个异常,同时希望这个异常能够被其它调用的部分使用。
finally用来执行那些无论异常是否发生都执行的操作。

void _testFinally({demo:100}) {
  try {
    print(" "+demo);
  } catch (e) {
    print('2');
    rethrow;
  }
}
void main() {
  try {
    _testFinally();
  } catch (e) {
    print('3');
  } finally {
    print('4'); // 即使没有rethrow最终都会执行到
  }
}
运行结果:
2
3
4

Dart 是一种面向对象的语言,并且支持基于mixin的继承方式:一个类可以继承自多个父类。
使用new语句来构造一个类。构造函数的名字可能是ClassName,也可以是ClassName.identifier。例如:

class Person{
  var _name;
  Person(){}
  Person.initName(this._name);
}
void main() {
  //使用new初始化对象
  var person = new Person();
  //使用ClassName.identifier初始化对象
  var person1 = Person.initName("xiaojian");
}
  • 使用.来调用实例的变量或者方法。
  • 使用 ?. 来避免左边操作数为null引发异常。
  • 使用const替代new来创建编译时的常量构造函数。
  • 两个使用const构建的同一个构造函数,实例相等。
  • 获取对象的运行时类型使用:o.runtimeType。
实例化变量

在类定义中,所有没有初始化的变量都会被初始化为null。
所有实例变量会生成一个隐式的getter方法,不是final或const的实例变量也会生成一个隐式的setter方法。

构造函数

构造函数不能被继承,如果不显式提供子类的构造函数,系统就提供默认的构造函数。

class Base{
  //父类构造函数
  Base(){
    print("base init");
  }
}

class Person extends Base{
  var _name;
  var _interest;
  //默认构造函数
  Person(){}
  //命名构造函数
  Person.initNameAndAge(this._name,this._interest);
  //重定向构造函数
  Person.initName(name):this.initNameAndAge(name,"无");
}

class RockerAddress {
  final num lat;
  final num lng;
  //常量构造函数
  const RockerAddress(this.lat, this.lng);
  static final RockerAddress address =
  const RockerAddress(39.19, 141.32);
}

class Logger {
  final String name;
  bool isDebug = false;
  // 命名构造函数
  Logger._internal(this.name);
  // 缓存保存对象
  static final Map<String, Logger> _cache = <String, Logger>{};
  //工厂构造函数
  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = new Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }
  void log(String msg) {
    if (!isDebug) {
      print(msg);
    }
  }
}

void main() {
  //person demo
  var person = new Person();
  var person1 = Person.initNameAndAge("xiaojian","pingpang");
  var person2 = Person.initName("jim");

  //rockaddress demo
  var rockaddress = RockerAddress.address;
  print(rockaddress.toString());

  //logger demo
  var p1 = new Logger("1");
  p1.log("2");
  var p2 = new Logger('22');
  p2.log('3');
  // 相同对象直接访问缓存
  var p3 = new Logger('1');
  print(p1==p3);
}
运行结果:
base init
base init
base init
Instance of 'RockerAddress'
2
3
true
  • 默认构造函数

没有声明构造函数,dart会提供默认构造函数。默认构造函数没有参数,并且调用父类的无参数构造函数。

  • 命名构造函数

使用命名构造函数可以实现一个类多个构造函数。构造函数不能被继承,父类中的命名构造函数不能被子类继承。如果想要子类也拥有一个父类一样名字的构造函数,必须在子类实现这个构造函数。

  • 重定向构造函数

有时候构造函数的目的只是重定向到该类的另一个构造函数。重定向构造函数没有函数体,使用冒号:分隔。

  • 常量构造函数

如果类的对象不会发生变化,可以构造一个编译时的常量构造函数。定义格式如下:
定义所有的实例变量是final。
使用const声明构造函数。

  • 工厂构造函数

当实例化了一个构造函数后,不想每次都创建该类的一个新的实例的时候使用factory关键字,定义工厂构造函数,从缓存中返回一个实例,或返回一个子类型的实例。
工厂构造函数不能访问this

  • 初始化列表

除了调用父类的构造函数,也可以通过初始化列表 在子类的构造函数体前(大括号前)来初始化实例的变量值,使用逗号,分隔。如下所示:
一个初始化器的右边不能访问this。

class Point {
  num x;
  num y;
  Point(this.x, this.y);
  // 在构造函数体前 初始化列表 设置实例变量
  Point.fromJson(Map jsonMap)
      : x = jsonMap['x'],
        y = jsonMap['y'] {
    print('In Point.fromJson(): ($x, $y)');
  }
}
  • 调用父类的非默认构造函数

默认情况下,子类调用父类的无参数的非命名构造函数。父类的构造函数会在子类的构造函数体之前(大括号前)调用。如果也使用了初始化列表 ,则会先执行初始化列表 中的内容,即下面的顺序:
初始化列表
父类无参数构造函数
主类无参数构造函数

如果父类不显式提供无参的非命名构造函数,在子类中必须手动调用父类的一个构造函数。在子类构造函数名后,大括号{前,使用super.调用父类的构造函数,中间使用:分割。
父类构造函数参数不能访问this,例如,参数可以调用静态方法但不能调用实例方法。

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // 父类没有无参数的非命名构造函数,必须手动调用一个构造函数 super.fromJson(data)
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}

抽象类

使用abstract关键字定义一个抽象类,抽象类不能实例化,抽象类通常用来定义接口,抽象类通常会包含一些抽象的方法。

//定义抽象类
abstract class Base{
  //定义抽象方法
  void doSomething();
}
方法
  • 实例方法
    Getters and setters
    get()和set()方法是Dart 语言提供的专门用来读取和写入对象的属性的方法。每一个类的实例变量都有一个隐式的getter和可能的setter(如果字段为final或const,只有getter)。
    像++之类的操作符,无论是否明确定义了getter,都按预期的方式工作。为了避免意想不到的副作用,操作符调用getter一次,将其值保存在临时变量中。
class Rectangle {
  num left;
  num top;
  num width;
  num height;

  Rectangle(this.left, this.top, this.width, this.height);

  // Define two calculated properties: right and bottom.
  num get right             => left + width;
  set right(num value)  => left = value - width;
  num get bottom            => top + height;
  set bottom(num value) => top = value - height;
}
void main() {
  var rect = new Rectangle(3, 4, 20, 15);
  print(rect.left == 3);
  rect.right = 12;
  print(rect.left == -8);
}
运行结果:
true
true
  • 抽象方法
    抽象方法,只有函数声明,没有函数体,作为接口在其他类中实现。调用抽象方法会导致运行时错误。如果在不是抽象类中定义抽象方法会引发warning,但不会阻止实例化。
abstract class Base{
  //定义抽象方法
  void doSomething();
}

class Child extends Base{
  @override
  void doSomething() {
      print("test");
  }
}
  • 静态变量和方法
    使用static关键字来实现类范围内变量和方法。
    静态方法不能被实例调用,不能访问this,只能被类名调用。
    对于通用或广泛使用的工具和功能,应该使用顶级函数,而不是静态方法。
    可以使用静态方法作为编译时常量。例如,可以给一个常量构造函数,传递一个静态方法作为参数。
class SecurityUtil{
  //静态变量
  static const key = "Encryption key is generally static";
  //静态方法
  static String md5(String){
  }

}
隐式接口

每一个类都隐式的定义一个接口,这个接口包含了这个类的所有实例成员和它实现的所有接口。
一个类可以实现一个或多个(用,隔开)接口,通过implements关键字。

class Person{
  final _name;
  Person(this._name);
  String greet(who) => 'hello,$who,i am $_name';
}

//implements关键字
class Imposter implements Person {
  final _name = '';
  String greet(who) => 'hi $who.do you know who i am.';
}

greetBob(Person p) => p.greet('jim');

void main() {
  print(greetBob(new Person('wangxiaojian')));
  print(greetBob(new Imposter()));
}
运行结果:
hello,jim,i am wangxiaojian
hi jim.do you know who i am.
继承

使用extends来创造子类,使用super来指向父类。
子类可以重载实例方法,使用@override注解重载方法。

class Person {
  final _name;
  Person(this._name);
  void printName() {
    print("base name = $_name");
  }
}

class Imposter extends Person {
  Imposter(name) : super(name);

  @override
  void printName() {
    print("child name = $_name");
  }
}

void main() {
  new Person("wangxiaojian").printName();
  new Imposter("wangxiaojian").printName();
}
运行结果:
base name = wangxiaojian
child name = wangxiaojian
枚举类型
  • 枚举类型是一种特殊的类,通常用来表示一组固定数字的常量值。
    使用enum关键字声明枚举类型。
  • 每个枚举类型都有一个index,返回以0开始的位置索引,每次加1
  • 使用values关键字获取枚举的所有值,返回一个列表。
  • 不能继承,mixin,或实现一个枚举;不能显式的实例化一个枚举。
enum Week {
  Monday,
  Tuesday,
  wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}

void main() {
  print(Week.Monday.index ==0);
  print(Week.Tuesday.index ==1);
  print(Week.wednesday.index ==4);
}
运行结果:
true
true
false
[Week.Monday, Week.Tuesday, Week.wednesday, Week.Thursday, Week.Friday, Week.Saturday, Week.Sunday]
minxins

mixins是一种在多个类层次结构中,重用一个类的代码的方法。使用with关键字后跟多个mixin名。

class Speak{
  void speak(){
    print(this.runtimeType.toString()+"  speak");
  }
}
class Walk{
  void walk(){
    print(this.runtimeType.toString()+ " walk");
  }
}
class Base{

}
class Person extends Base with Speak,Walk{

}
class Animal extends Base with Speak,Walk{

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

推荐阅读更多精彩内容

  • 此文章是v1.0+时编写,年代久远,小心有毒,谨慎食用!!! 一些重要概念 所有的东西都是对象,所有的对象都是类的...
    soojade阅读 10,047评论 2 27
  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,350评论 8 265
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,605评论 18 399
  • 怀孕时总想象自己生出来的是惊天动地的奇才,孩子出生后总感觉自己的孩子是无与伦比的聪明,举世无双的帅气。孩子...
    胡炎鸾玉阅读 241评论 0 1
  • 玉花纷飞的日子里, 看多少相思走进白头; 冰雪奇缘中, 盼飒飒寒霜掬新水。 而我 在春的这边 等 你
    深海醉春独伊人阅读 155评论 0 2