02 - Dart笔记-基础语法

2018-12-28  本文已影响0人  云佾风徽

基础语法

[TOC]

官方文档

中文文档

变量

dart是强类型

var

由类型推断确定变量类型

dynamic

可以动态改变变量类型

final

与java相同,只能赋值一次

const

声明为常量

常量的值可以是全为常量的表达式,例如常量相加,常量字符串插值

内建类型

numbers

int

平台不同,不超过64位

double

64位(双精度)浮点数

字面值的方法

与kotlin一样,字面值也可以调用方法,例如:

var tmp = 3.14159.toStringAsFixed(2);

字符与number互转

int aInt = 10;
double aDouble = 3.1415;
String aIntStr = "123";
String aDoubleStr = "5.312";

var bInt = int.parse(aIntStr);
var bDouble = double.parse(aDoubleStr);
var stringFromInt = aInt.toString();
var stringAsFixed = aDouble.toStringAsFixed(2);

String

void useString() {
  // 1. 单引号 双引号
  var a = 'Single quotes';
  var b = 'Double quotes';
  var c = "I'm ok";
  var d = 'It\'s wrong';

  // 2. 插值表达式
  int x = -100;
  var e = "check i = $x";
  var f = "abs i = ${x.abs()}";

  // 3. 字符重复
  var g = "am${'a' * 10}zing";
  var h = "a${"ma" * 10}zing";

  // 4. 字符串拼接
  var i = "Welcome " 'to ' "China";
  var j = "I'm" + " " + "tired";

  // 5. 多行字符串
  var k = '''
Initializing gradle...
Resolving dependencies...
Gradle task 'assembleDebug'...''';
  var l = """
Performing hot reload...
Syncing files to device Android SDK built for x86...
Reloaded 3 of 422 libraries in 428ms.""";
  // 6. 原始字符串
  var m = r"will not \n start a new line";

  print(
      "use String:\n$a\n\n$b\n\n$c\n\n$d\n\n$e\n\n$f\n\n$g\n\n$h\n\n$i\n\n$j\n\n$k\n\n$l\n\n$m");
}

布尔类型bool

bool aBool = true;

非bool类型的值不能做为表达式的判断

// isEmpty查空串
var fullName = '';
assert(fullName.isEmpty);

// 检查数值
var hitPoints = 0;
assert(hitPoints <= 0);

// null判空
var unicorn;
assert(unicorn == null);

// isNaN算术 NaN
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

列表/数组类型List<E>

void useList() {
  List<int> list = [1, 2, 3];
  list[0] = list.length;
  print("list's 0 item = ${list[0]}");

  var constList = const [9,8,7];
  print(constList);
}

字典/映射表类型Map<K,V>

Map<int, String> map = {1: "1", 4: "4"};
map[10] = "10";
var tmp = map[4];
assert(null == map[7]);
map[1] = map.length.toString();
var constMap = const {1: 2, 3: 4};
print(map);

Runes

void useRunes() {
  String unicodeStr = '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  '
      '\u{1f44d}';

  // String 转 runes
  var runes = unicodeStr.runes;
  runes = new Runes(unicodeStr);
  // runes 转 String
  var string = String.fromCharCodes(runes);


  print("unicode string: ${unicodeStr}");
  print("unicode string in utf16: ${unicodeStr.codeUnits}");
  print("unicode string in utf32: ${unicodeStr.runes.toList()}");

}

symbols

函数

=>单表达式函数

=>expr 等价于 {return expr;}

参数列表

可选参数

与Java的可变参类似。

给一个函数定义可选参数,只能选择位置参数或者命名参数中的一种,不能同时使用两者

参数默认值
位置参数
命名参数
testVA() {
  testParamPos(1);
  // 位置参数使用时不能带上参数名
  // The named parameter 'c' isn't defined.
//  testParamPos(2, c:"e");
  // 位置参数不能跳过中间的参数
  // The argument type 'int' can't be assigned to the parameter type 'String'
//  testParamPos(2, 1);
  testParamPos(2, "a");
  testParamPos(3, "b", 4);

  testParamName(1);
  testParamName(2, d: 6);
  // 命名参数必须带上参数名
  // too many positional arugments ...
//  testParamName(2,5,8);
  testParamName(3, c: 7);
  testParamName(4, c: 8, d: 0);
  testParamName(5, d: 9, c: 0);
}

//testParam(int req,[int c],{int a= 100,int b=300}){}
//testParam(int req,{int a= 100,int b=300},[int c]){}
testParamPos(int req, [String c = "h", int d]) {}

testParamName(int req, {int c = 8, int d}) {}

返回值

没有指定返回值,则返回值为null,类似js undefined

main

应用程序入口是一个顶层函数main

void main(){}
void main(List<String> args){}

函数也是对象

int sum = 0;

countSum(int val) {
  sum += val;
}

testFunction() {
  var list = [32, 123, 43, 31, 55, 346, 786];
  sum = 0;
  list.forEach(countSum);
  print(sum);

  var addFunc = (int a, int b) {
    return a + b;
  };
  var minusFunc = (int a, int b) => a - b;

  print(addFunc(4, 3));
  print(minusFunc(4, 3));
}

判断函数引用是否相等

转载一个demo看看就行了

void foo() {} // A top-level function

class A {
  static void bar() {} // A static method
  void baz() {} // An instance method
}

void main() {
  var x;

  // Comparing top-level functions.
  x = foo;
  assert(foo == x);

  // Comparing static methods.
  x = A.bar;
  assert(A.bar == x);

  // Comparing instance methods.
  var v = A(); // Instance #1 of A
  var w = A(); // Instance #2 of A
  var y = w;
  x = w.baz;

  // These closures refer to the same instance (#2),
  // so they're equal.
  assert(y.baz == x);

  // These closures refer to different instances,
  // so they're unequal.
  assert(v.baz != w.baz);
}

匿名函数/lambda/闭包

testAnonymousFunction() {
  var list = [1, 5, 31, 57, 231, 6, 234, 7];
//  list.forEach({
//    print(it);
//  });
//  list.forEach(
//    print(it);
//  );
  list.forEach((it) => print(it));

  list.forEach((it) {
    print(it);
  });
}

函数中变量的作用域

testNestedFunction() {
  int a = 12;
  void myNested() {
    int b = 43;

    void nest() {
      int c = 55;
      // 内层函数能够访问到外层函数的变量
      a = 10;
    }
  }

  // 外层函数访问不到内层函数的变量
  // undefined name 'b'
//  b = 10;
}

闭包传递的参数

闭包会捕获定义在其声明位置的作用域内的变量。即使闭包函数在其声明位置之外的作用域使用,也会记住被捕获的变量

A closure is a function object that has access to variables in its lexical scope, even when the function is used outside of its original scope.

Functions can close over variables defined in surrounding scopes. In the following example, makeAdder()captures the variable addBy. Wherever the returned function goes, it remembers addBy.

testClosureArgument() {
  makeClosure(int a) {
    return (num val) => val + a;
  }

  Function addClosure2 = makeClosure(2);
  Function addClosure3 = makeClosure(3);

  print(addClosure2(5));
  print(addClosure3(5));

  Function minusClosure2;
  Function minusClosure3;

  makeClosure2(int b) {
    b = 2;
    minusClosure2 = (num val) => val - b;
    b = 3;
    minusClosure3 = (num val) => val - b;
  }

  makeClosure2(9);

  print(minusClosure2(5));
  print(minusClosure3(5));

  makeClosure3(int c) {
    Function build(int i) {
      return (num val) => val * i;
    }

    var list = new List(c);
    for (int j = 0; j < c; j++) {
      list[j] = build(j);
    }
    return list;
  }

  var funcList = makeClosure3(5);

  funcList.forEach((func) => print(func(2)));

  makeClosure4(int c) {

    var list = new List(c);
    for (int j = 0; j < c; j++) {
      list[j] = (num val) => val * j;
    }
    return list;
  }

  var funcList2 = makeClosure4(4);

  funcList2.forEach((func) => print(func(3)));


  print("next>>>>>");
  makeClosure5(int c) {

    int len  = c;
    var list = new List(c);
    for (int j = 0; j < len; j++) {
      c = j;
      list[j] = (num val) => val * c;
    }
    return list;
  }

  makeClosure5(6).forEach((func) => print(func(4)));


}

此例中,makeClosure2和makeClosure5中,传入闭包的并不是在其声明位置的函数中定义的变量,而是形参。结果就失效,闭包只能记住形参最后一次的值。

运算符

按照优先级排列

描述 操作符
一元后置操作符 expr++    expr--    ()    []    .    ?.
一元前置操作符 -expr    !expr    ~expr    ++expr    --expr
乘除运算 *    /    %    ~/
加减运算 +    -
移位运算 <<    >>
按位与 &
按位异或 ^
按位或 |
关系和类型测试 >=    >    <=    <    as    is    is!
相等 ==    !=
逻辑与 &&
逻辑或 ||
是否为null ??
天健判断(三元运算) expr1 ? expr2 : expr3
级联 ..
赋值 =    *=    /=    ~/=    %=    +=    -=    <<=    >>=    &=    ^=

要注意的运算符

级联运算

testCascade() {
  var user = User()
    ..age = 10
    ..name = "rexih"
    ..id = 1021
    ..setAlias("Lisa")
    ..sex = 1;
  print(user);
  // 类的静态方法,不论是正常调用还是级联运算,都不能通过实例对象调用
  // Static method 'setNice' can't be accessed through an instance
//  user.setNice(false);
//  user..setNice(false);

  StringBuffer sb = new StringBuffer();
  sb.write("aa");
  sb..write("a")..write("b");
  print(sb.toString());

  // 级联操作只能从实例对象或者一个返回实例对象的方法开始,
  // 后续操作都是起始对象可以调用的成员方法
  // 级联操作相当于调用了成员方法后,又返回了实例对象交由下一个方法使用
  // The expression here has a type of 'void', and therefor cannot be used
//  sb.write("v")
//  ..write("c");

  var name = User().findName();
  // 级联操作可以从实例变量开始
  var s = name
    ..substring(2);
  // s的值没有变,因为级联操作只是为了处理被操作的对象,
  // 赋值给另一个变量的不是方法的返回值,而是级联起始的对象
  print(s);
  String findName = User().findName()
    ..substring(1)
    ..toUpperCase();
  print(findName);
}

class User {
  int id;
  String name = "anonymous";
  int sex;
  int age;

  void setAlias(String alias) {
    name = alias;
  }

  String findName() => name;

  @override
  String toString() {
    return 'User{id: $id, name: $name, sex: $sex, age: $age}';
  }
}

流程控制

for循环

  1. 正常for循环

  2. forEach循环

  3. for in循环

      var list = [4, 5, 2];
      for (var a in list) {
        print(a);
      }
    
  4. 关于官方文档中说可以避免js的闭包问题,跟之前说的传入闭包的参数一样,看传入的变量是否是在闭包声明位置的作用域内定义,如果不是,仍然捕获不到

    void testFor() {
      var callbacks = [];
      for (var j = 0; j < 5; j++) {
        callbacks.add(() => print(j));
      }
      callbacks.forEach((c) => c());
    
      callbacks.clear();
      print("show error");
      int i = 0;
      for (; i < 9; i++) {
        callbacks.add(() => print(i));
      }
      callbacks.forEach((c) => c());
    }
    

    运行结果

    I/flutter (30393): 0
    I/flutter (30393): 1
    I/flutter (30393): 2
    I/flutter (30393): 3
    I/flutter (30393): 4
    I/flutter (30393): show error
    I/flutter (30393): 9
    I/chatty  (30393): uid=10099(cn.rexih.flutter.flutterapp2) Thread-2 identical 7 lines
    I/flutter (30393): 9
    

switch

dart的switch支持字符串,整数和编译时常量,但是一个switch中只能比较一种类型

assert

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');

异常

异常捕获

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  //只捕获异常,不处理异常对象
  buyMoreLlamas();
} on Exception catch (e) {
  //处理异常对象
  print('Unknown exception: $e');
  //在捕获中重新抛出
  rethrow;
} catch (e, s) {
  //处理StackTrace堆栈跟踪对象
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
} finally {
  cleanLlamaStalls();
}

上一篇 下一篇

猜你喜欢

热点阅读