Dart语言笔记(一)

Dart语言笔记(二)

1.重要概念

  • 一切变量都是对象,包括数字、函数和null
  • 对象是类的实例,所有类都继承于Object
  • 强类型但支持类型推断
  • 如果不想指定具体类型可以使用dynamic
  • 支持泛型,比如List<int>List<daynamic>
  • 支持顶层函数、类方法、实例方法和嵌套函数
  • 支持顶层变量、类变量、实例变量和局部变量
  • 以下划线_打头的变量为私有,只能在库(Library)内部使用
  • 标识符只能以字母或下划线打头,后面跟任意多个字符、数字或下划线字符
  • 表达式在运行时可以求值,而语句不行
  • 代码问题分为warning和error两种,warning不会阻止程序运行,但error会
  • error分为编译时错误和运行时错误两种,运行时错误会导致抛出异常

2.变量

  • 变量类型可自动推断,或者显示指定
  • 未初始化的变量其值都是null,包括数字
  • 如果某个变量的值在定义后不会再改变,那就声明为finalconst
  • finalconst变量只能赋值一次,但const变量的值需要在编译时就能确定
  • finalconst变量必须在其定义时就完成初始化
  • const变量的值须为编译时常量,包括数字和字符串字面量、其他常量或算术运算结果
  • const除了用来声明变量,也可用来声明值,也就是常值
  • 初始化const变量时可以省去值前面的const,因为const变量的值肯定得是一个常值
  • 常值用来防止内容变化,常量用来避免变量寻址,final变量用来提升代码安全性

3.内置类型

  • 数字(num)
    • num是int和double的基类
    • int为64位整数,double为64位浮点数
  • 字符串(String)
    • 字符串是UTF-16码元(Code Unit)序列,每个Unicode字符映射为1个或2个码元
    • 字符串字面量可以使用单引号或双引号
    • 使用${expression}来插入变量值,如果expression是个合法的标识符,则可以省去{}
    • 使用毗连字符串常量或者+操作符来拼接字符串
    • 使用三重引号(三重单引号或者三重双引号都可以)来定义多行字符串
    • 使用r前缀来声明原始字符串,其内不作字符转义
    • 只要内部插入的表达式为编译时常量,则字符串字面量为编译时常量
  • 布尔(bool)
    • 只有两个值true和false,都是编译时常量
    • 在需要布尔类型的地方必须使用布尔值,没有非零即真的概念
  • 列表(List)
    • 列表就是其他语言里的数组,用来表示对象序列
    • 列表索引序号从0开始,直到list.length-1
    • 在列表字面量前使用const来声明常值
    • 使用[]操作符来操作列表元素
  • 哈希表(Map)
    • 哈希表用来关联键和值,键和值可以是任意类型的对象,但键必须唯一
    • 使用[]操作符来操作哈希表的值
    • 在哈希表字面量前使用const来声明常量
  • 符文(Rune)
    • Rune是UTF-32码点(Code Point)组成的字符串,一个Rune字符对应一个Unicode字符
    • 码点一般使用4个十六进制字符\uXXXX来表示,如果超过4个,则需要使用{}将十六进制字符括起来
    • 字符串和Rune可以直接互相转换
  • 符号(Symbol)
void main() {
  var x = 1;
  var hex = 0xDEADBE;

  var y = 1.1;
  var exponents = 1.42e5; //科学计数法

  double z = 1;

  var addIntAndDouble = x + y; //int可以直接和double计算,会隐式转换为double
  assert(addIntAndDouble == 2.1);

  var one = int.parse('1'); //使用parse解析字符串
  assert(one == 1);

  var onePintOne = double.parse('1.1');
  assert(onePintOne == 1.1);

  String oneAsString = 1.toString(); //使用toString转换为字符串
  assert(oneAsString == '1');

  String piAsString = 3.1415926.toStringAsFixed(2); //转换为string并保留几位小数
  assert(piAsString == '3.14');

  assert((3 << 1) == 6);
  assert((3 >> 1) == 1);
  assert((3 | 4) == 7);

  //定义常量
  const msPerSecond = 1000;
  const secondsUntilRetry = 5;
  const msUntilRetry = secondsUntilRetry * msPerSecond;

  var s1 = 'Single string'; //单引号
  var s2 = "Double string"; //双引号
  var s3 = 'It\'s easy'; //转义字符
  var s4 = "It's easy"; //双引号中单引号就不用加转移字符

  var s = 'string';
  var uppeers = s.toUpperCase(); //转化为大写
  assert(uppeers == 'STRING');
  assert(s == uppeers.toLowerCase()); //转化为小写

  //使用毗连字符串拼接
  s1 = 'String '
      'concat '
      'work';
  assert(s1 == 'String concat work');

  //使用+连接字符串
  s2 = 'String ' + 'concat ' + 'work';
  assert(s2 == 'String concat work');

  //使用'''或者"""定义多行字符串
  s2 = '''String
       concat
       work''';

  //在字符串前加r定义不转义的字符串
  s = r'In a raw string,not even \n gets special treatment';

  const aConstNum = 0;
  const aConstBool = true;
  const aConstString = 'a const string';

  var aNum = 0;
  var aBool = true;
  var aString = 'a string';
  //定义一个List常量
  const aConstList = [1, 2, 3];

  //后面都是常量,而且表达式编译时可确定值,所以可以赋值给一个常量字符串
  const validConstString = '$aConstNum $aConstBool $aConstString';
  // const invalidConstString = '$aNum $aConstNum $aConstBool $aConstString';

  var fullName = '';
  assert(fullName.isEmpty); //使用isEmpty来判空

  var hitPoints = 0;
  assert(hitPoints <= 0);

  //未初始化默认都是null
  var unicorn;
  assert(unicorn == null);

  //这个不会抛出异常,类型是double,但是值是NaN
  var iMeantToDoThis = 0 / 0;
  print(iMeantToDoThis);
  print(iMeantToDoThis.runtimeType);
  assert(iMeantToDoThis.isNaN);

  var list = [1, 2, 3];
  assert(list.length == 3);
  assert(list[1] == 2);
  list[1] = 22;
  assert(list[1] == 22);

  //给list赋常值
  var constList = const [1, 2, 3];
  //常值的内容不能被改变
  // constList[1] = 22;

  //Map定义
  var gifts = {
    'first': 'part',
    'seconed': 'tue',
    'fifth': 'golden',
  };
  print(gifts.runtimeType); //JsLinkedHashMap<String, String>

  var nobleGases = {2: 'helium', 10: 'neon', 18: 'argon'};
  print(nobleGases.runtimeType); //JsLinkedHashMap<int, String>

  //构造函数方式创建Map
  gifts = Map();
  gifts['first'] = 'part1';
  gifts['seconed'] = 'tue1';
  gifts['fifth'] = 'golden1';

  gifts = {'first': 'part1'};
  assert(gifts['fifth'] == null);

  gifts['seconed'] = 'tue';
  assert(gifts.length == 2);

  //常值Map
  final constMap = const {
    2: 'helium',
    10: 'neon',
    18: 'argon',
  };
  //final定义的只能一次赋值
  // constMap = Map();
  //常量不能修改内容
  // constMap[20] = 'tw';

  //每两个十六进制占一个字节,这里占3个字节,所以需要大括号括起来
  var clapping = '\u{1f44f}';
  print(clapping); //👏
  // 打印码云序列,需要两个码云
  print(clapping.codeUnits); //[55357, 56399]
  // 转化为一个runes,得到runes的码点序列
  print(clapping.runes.toList()); //[128079]

  //小于等于2个字节不用加大括号
  Runes input =
      Runes('\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
  //fromCharCodes:根据Unicode编码序列来得到字符串
  print(String.fromCharCodes(input)); //♥ 😅 😎 👻 🖖 👍
}

4.函数

  • 函数也是一种对象,类型为Function
  • 函数参数和返回值类型可省略,以支持动态类型
  • 如果函数体只包含一个表达式,可使用箭头语法来定义
  • 可选参数
    • 可选命令参数使用{}来指定,并且可使用注解@required标注为必需
    • 可选位置参数使用[]来指定
    • 可选参数默认值使用=来指定,如未指定则默认值为null
  • 每个dart程序都应该有个位于顶层的main函数,它是程序的入口
  • 函数可作为函数参数值,也可以赋值给变量
  • 可定义匿名函数,一般作为函数参数值或赋值给变量
  • 变量作用域静态确定,也就是同代码布局,每对大括号定义一个作用域,嵌套大括号定义嵌套作用域
  • 闭包是一个能访问其外层作用域变量的函数,即便该函数在其他地方被调用
  • 如果函数没有指定返回值,则默认返回null,如果确实不想返回任何值,则可指定返回类型为void
//全局变量 是否顶层
bool topLevel = true;
void main() {
  var _nobleGases = {
    2: 'helium',
    10: 'neon',
    18: 'argon',
  };

  //最普通的函数定义
  bool isNoble(int atomicNumber) {
    return _nobleGases[atomicNumber] != null;
  }

  //dart是一门兼具动态性和静态性的语言
  //未指定参数类型,那么参数类型就是dynamic
  //返回值为bool类型可以推断出来
  //所以返回值类型和参数类型都可以省略
  isNobleDynamic(atomicNumber) {
    return _nobleGases[atomicNumber] != null;
  }

  //单行表达式可以使用箭头
  bool isNobleArrow(int atomicNumber) => _nobleGases[atomicNumber] != null;

  //可选命名参数需要放在{}中
  void enableFlags({bool? bold, bool? hidden}) {}
  //可选命令参数调用时需显式指定参数名
  enableFlags(bold: true, hidden: false);

  //位置参数放在[]中
  String say(String from, String msg, [String? device]) {
    var result = '$from says $msg';
    if (device != null) {
      result = '$result with a $device';
    }
    return result;
  }

  assert(say('Bob', 'Howdy') == 'Bob says Howdy');
  assert(say('Bob', 'Howdy', 'smoke signal') ==
      'Bob says Howdy with a smoke signal');

  //可选参数设置默认值
  void enableFlagsDefault({bool? bold = false, bool? hidden = false}) {}
  enableFlagsDefault(bold: true);

  String sayDefault(String from, String msg,
      [String? device = 'carrier pigeon', String? mood]) {
    var result = '$from says $msg';
    if (device != null) {
      result = '$result with a $device';
    }
    if (mood != null) {
      result = '$result (in a $mood mood)';
    }
    return result;
  }

  assert(sayDefault('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');

  void doStuff(
      {List<int> list = const [1, 2, 3],
      Map<String, String> gifts = const {
        'first': 'paper',
        'seconed': 'cotton',
        'third': 'leather'
      }}) {
    print('list: $list'); //list: [1, 2, 3]
    print(
        'gifts: $gifts'); //gifts: {first: paper, seconed: cotton, third: leather}
  }

  doStuff();

  void printElement(int element) {
    print(element);
  }

  var list1 = [1, 2, 3];
  list1.forEach(printElement);

  var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
  print(loudify('hello')); //!!! HELLO !!!

  var list2 = ['apples', 'bananas', 'oranges'];
  list2.forEach((item) {
    print('${list2.indexOf(item)}: $item');
  });
  //单行表达式可以换为箭头函数返回
  list2.forEach((item) => print('${list2.indexOf(item)}: $item'));

  //作用域嵌套
  var insideMain = true;
  void myFunction() {
    var insideFunction = true;

    void nestedFunction() {
      var insideNestedFunction = true;
      assert(topLevel);
      assert(insideMain);
      assert(insideFunction);
      assert(insideNestedFunction);
    }
  }

  //闭包,匿名函数
  Function makeAdder(num addBy) {
    return (num i) => addBy + i;
  }

  var add2 = makeAdder(2);
  var add4 = makeAdder(4);
  assert(add2(3) == 5);
  assert(add4(3) == 7);

  //无返回值默认返回值为null
  foo() {}
  assert(foo() == null);
}

5.操作符

  • 操作符有优先级,从高到低为一元后缀、一元前缀、乘除、加减、移位、位运算、关系运算和类型测试、相等性运算、逻辑运算、null判断、三元表达式、级联调用和赋值
  • 在优先级判断比较模糊的地方,使用()来提升可读性
  • 算术运算
    • +-*/-expr~/(整除)、%(求余)
    • ++varvar++--varvar--
  • 相等性和关系运算
    • ==!=><>=<=
    • ==判断值是否相等,如果要判断是否为同一个对象,使用identical()函数
  • 类型测试
    • as(类型转换)、is(判断是否指定类型)、is!(判断是否非指定类型)
  • 赋值
    • =??=(null则赋值,否则不赋值;一般用于初始化时防止重复初始化)
    • -=/=%=>>=^=+=*=~/=<<=&=|=
  • 逻辑运算
    • !expr(逻辑非)、||&&
  • 位运算
    • &|^(异或)、~expr(按位取反)、<<>>
  • 条件表达式
    • 三元表达式condition?expr1:expr2
    • null判断expr1 ?? expr2expr1为非null则取expr1的值,否则取expr2的值
  • 级联调用
    • ..,严格来说是dart独有的语法糖,一般用于在一个对象上连续的调用,比如同时设置多个成员的值。..会强制返回调用者对象,而忽略掉当前调用方法的返回值。
    • ?..,若调用者可能为null,则使用这个操作符,如果调用者对象为null,则不会触发访问,非null则继续访问。这个操作符后面继续级联调用可以继续使用..,因为..都是返回调用者对象。
  • 函数调用()
  • 下标访问[]
  • 成员访问.?.
  • 条件式成员访问?.: 如果调用者对象是null,,则不会访问成员,如果是非null,则访问成员
void main() {
  var a = 1;
  var b = 2;
  var c = true;
  print(a++);
  print(a + b);
  print(a = b); //赋值表达式的值就是赋值后变量的值
  print(a == b);
  print(c ? a : b);
  assert(a is int);

  var n = 4;
  var d = 6;
  var i = 2;
  assert((n % i == 0) && (d % i == 0));
  assert(n % i == 0 && d % i == 0);

  assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');

  a = 0;
  //前缀表达式,先自增/自减 再返回值
  b = ++a;
  print(b); //1

  a = 0;
  //后缀表达式 先返回变量值 再自增/自减
  b = a++;
  print(b); //0

  a = 0;
  b = --a;
  print(b); //-1

  a = 0;
  b = a--;
  print(b); //0

  List<dynamic> list = [1, 'a', 2, 'b'];
  if (list[1] is String) {
    print((list[1] as String).toUpperCase()); //A
  }

  a = 1;
  //b未赋值才执行赋值
  b ??= 2;
  print(b); //0

  var done = false;
  var col = 3;
  print(!done && (col == 0 || col == 3)); //true

  final value = 0x22;
  final bitmask = 0x0f;

  //转化为16进制打印输出
  print((value & bitmask).toRadixString(16)); //2
  print((value & ~bitmask).toRadixString(16)); //20
  print((value | bitmask).toRadixString(16)); //2f
  print((value ^ bitmask).toRadixString(16)); //2d
  print((value << 4).toRadixString(16)); //220
  print((value >> 4).toRadixString(16)); //2

  var isPublic = false;
  var visibility = isPublic ? 'public' : 'private';
  print(visibility); //private

  String playerName(String? name) => name ?? 'Guest';
  print(playerName(null)); //Guest

  String playerNameArrow(String? name) => name != null ? name : 'Guest';
  print(playerNameArrow(null)); //Guest

  String playerNameIf(String? name) {
    if (name != null) {
      return name;
    } else {
      return 'Guest';
    }
  }

  print(playerNameIf(null)); //Guest
  //级联操作符
  var sb = StringBuffer()
    ..write('foo')
    ..write('bar')
    ..write('test');
  print(sb);//foobartest
}

6.控制流程

  • If-else
    • 条件必须为布尔值
  • For loop
    • 循环内的闭包会捕获循环变量的当前值
    • 可迭代对象可使用for-in来迭代其内部元素
  • While、do-while
    • While先判断条件,满足后再执行循环体
    • do-while先执行一次再判断条件
  • Break、continue
    • Break终止循环,continue跳过本次循环剩余代码,直接进入下一次循环
  • Switch-case
    • 使用==操作符来比较整数、字符串或编译时常量,包括枚举类型
    • 非空case语句正常情况下应以break结束,也可使用continue、throw或return来结束
    • 使用default语句来匹配其他情况
    • 空case语句会落入下方case语句
    • 可结合使用continue和label来跳转到其它case语句
    • 一般用于解释器和扫描器,编写应用时尽量少用
  • Assert
    • 只在开发模式下有效,生产模式下会被忽略
    • 条件判断失败时会抛出AssertionError异常,可通过第二个参数指定错误消息
void main() {
  var isRaining = false;
  var isSnowing = true;
  //条件必须是bool类型
  if (isRaining) {
    print('bring rain coat');
  } else if (isSnowing) {
    print('wear jacket');
  } else {
    print('put top down');
  }

  //和C一样的for循环
  var message = StringBuffer('Dart is fun');
  for (var i = 0; i < 5; i++) {
    message.write('!');
  }

  //闭包捕获值
  var callbacks = [];
  for (var i = 0; i < 2; i++) {
    callbacks.add(() => print(i));
  }
  callbacks.forEach((c) => c());

  //for-in
  var collection = [0, 1, 2];
  for (var item in collection) {
    print(item);
  }

  //while
  var isDone = false;
  while (!isDone) {
    print('Do sth');
    isDone = true;
  }

  //do-while
  var atEndOfPage = true;
  do {
    print('do sth');
  } while (atEndOfPage == false);

  //break退出循环
  var shutDownRequested = false;
  while (true) {
    if (shutDownRequested) break;
    print('process incoming requests');
    shutDownRequested = true;
  }

  //continue进入下一次循环
  var candidates = [1, 3, 5, 2, 4, 7];
  for (var i = 0; i < candidates.length; i++) {
    var candidate = candidates[i];
    if (candidate < 5) {
      continue;
    }
    print('interview');
  }

  //switch case
  var command = 'OPEN';
  switch (command) {
    case 'CLOSED':
      print('execute closed');
      //continue配合label
      continue openCase;
    case 'PENDING':
      print('execute pending');
      break;
    //空的case语句,可以fall-through到下一个case
    case 'APPROVED':
    // print('execute approved');
    // break;
    case 'DENIED':
      print('execute denied');
      break;
    //定义了label
    openCase:
    case 'OPEN':
      print('execute open');
      break;
    default:
      print('execute unknown');
  }

  var urlString = 'https://www.google.om/';
  //assert两个参数,第一个是bool表达式,第二个是可选的描述字符串
  assert(urlString.startsWith('https'),
      'URL ($urlString) should start with "https".');
}

7.异常

  • 异常表示有一些预料之外的错误发生了
  • 如果异常未被捕捉,则程序将终止运行
  • Dart内置了Exception和Error两种类型,Exception核心库异常,Error用于应用代码异常
  • 可使用throw抛出任何非null对象作为异常
  • throw语句是一个表达式
  • 使用try-catch语句来捕捉异常,以防止异常扩散,同时可使用on语句来处理特定类型的异常
  • 使用rethrow来再次抛出异常
  • 使用finally语句来执行无论是否出现异常都要运行的代码
void main() {
  void foo() => throw UnimplementedError();

  try {
    foo();
  } on UnimplementedError catch (e) {
    // on表示明确捕捉某种异常
    print('Unknown exception: $e'); //Unknown exception: UnimplementedError
  } catch (e, s) {
    // 第一个参数e是异常参数,第二个参数s异常调用栈
    print('Exception details:\n $e');
    print('Stack trace:\n $s');
  }

  void misbehave() {
    try {
      dynamic foo = true;
      print(foo++);
      //布尔值无法执行++操作
    } catch (e) {
      print(
          'misbehave() partinally handled ${e.runtimeType}'); //misbehave() partinally handled JsNoSuchMethodError
      //这里还没处理完,还需要外层继续处理,rethrow继续抛出
      rethrow;
    }
  }

  try {
    misbehave();
  } catch (e) {
    print(
        'main() finished handling ${e.runtimeType}'); //main() finished handling JsNoSuchMethodError
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容