Dart语法基础笔记(一)

官网地址:https://dart.dev/guides/language/language-tour
中文网地址:http://dart.goodev.org/guides/language/language-tour#comments

由于官网上的内容是最新的,中文网上无法即时更新文档,所以这里摘录一下和Java或者Kotlin不同的地方。

Final and const

如果你以后不打算修改一个变量,使用 final 或者 const。 一个 final 变量只能赋值一次;一个 const 变量是编译时常量。 (Const 变量同时也是 final 变量。) 顶级的 final 变量或者类中的 final 变量在 第一次使用的时候初始化。

⚠️注意:实例变量可以是final的,但不能是const的,

final name = "CYC";
final String name = 'CYC'

const 变量为编译时常量。 如果 const 变量在类中,请定义为 static const。 可以直接定义 const 和其值,也 可以定义一个 const 变量使用其他 const 变量的值来初始化其值。

?️这里使用final和使用const的区别是什么呢?

一些场景中,const不用多次冗余来声明
如:

const baz = []; // Equivalent to `const []`

//应该使用:
const primaryColors = [
  Color("red", [255, 0, 0]),
  Color("green", [0, 255, 0]),
  Color("blue", [0, 0, 255]),
];

//冗余的使用
const primaryColors = const [
  const Color("red", const [255, 0, 0]),
  const Color("green", const [0, 255, 0]),
  const Color("blue", const [0, 0, 255]),
];

Number类型

从Dart2.1开始,支持数值类型的自动转型,

double z = 1; // Equivalent to double z = 1.0.

Collection

List

Dart中的list就是数组,使用如下:

var list = [1, 2, 3];//Dart的类型推断出list类型为List<int>

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

创建一个编译时list常量,直接在数组字面量前面加上const ,

var constantList = const [1, 2, 3];
// constantList[1] = 1; // Uncommenting this causes an error.

Dart 2.3 开始在Set,List,Map中引入spread operator (…)null-aware spread operator (…?),使得在向一个Collection集合中插入元素时更加方便,如:

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);

Dart 2.3 开始引入collection ifcollection for,在创建Collection时,可以使用条件if和循环for来构建,如:

var nav = [
  'Home',
  'Furniture',
  'Plants',
  if (promoActive) 'Outlet'
];

var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');

Set

可以使用以下两种方式创建一个set,

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.

⚠️注意: 如果没有在{ }前面加上范型类型或者变量没有指定类型,那么直接使用{ }默认是创建了一个类型为Map<dynamic, dynamic>的Map。

创建一个编译时常量set,可以在set字面量之前加上const, 如:

final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.

Map

创建map的方式,同Set,

//直接使用Map字面量声明
var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

//使用Map的构造函数
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

#Functions
单函数表达式使用“ =>”

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

可以使用[ ] 表示可选的参数,函数参数默认值可以使用“=”表示,

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');

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}

// bold will be true; hidden will be false.
enableFlags(bold: true);

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

函数也是一种类型,可以作为参数和返回值,可以把一个函数赋值给一个变量

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

var list = [1, 2, 3];

// Pass printElement as a parameter.
list.forEach(printElement);

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

//返回一个函数类型
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

void main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}

匿名方法,有时候也被成为lambda或者闭包 closure,如果函数体就只有一个语句,可以使用“=>”简化

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

list.forEach(
    (item) => print('${list.indexOf(item)}: $item'));

#Operators

a = value;   // 给 a 变量赋值
b ??= value; // 如果 b 是 null,则赋值给 b;
             // 如果不是 null,则 b 的值保持不变

Conditional expressions(条件表达式)

Dart 有两个特殊的操作符可以用来替代 if-else 语句:

 condition ? expr1 : expr2

如果 condition 是 true,执行 expr1 (并返回执行的结果); 否则执行 expr2 并返回其结果。

expr1 ?? expr2

如果 expr1 是 non-null,返回其值; 否则执行 expr2 并返回其结果。

对于实现 Iterable 接口对象上,可以使用以下简化的形式:

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}

candidates.where((c) => c.yearsExperience >= 5)
          .forEach((c) => c.interview());

构造函数

由于把构造函数参数赋值给实例变量的场景太常见了, Dart 提供了一个语法糖来简化这个操作

class Point {
  num x;
  num y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}

Initializer list(初始化列表)

在构造函数体执行之前除了可以调用超类构造函数之外,还可以 初始化实例参数。 使用逗号分隔初始化表达式。
可以使用重定向的构造函数,直接引用主构造函数

class Point {
  num x;
  num y;

  Point(this.x, this.y);

  // Initializer list sets instance variables before
  // the constructor body runs.
  Point.fromJson(Map jsonMap)
      : x = jsonMap['x'],
        y = jsonMap['y'] {
    print('In Point.fromJson(): ($x, $y)');
  }
}

//重定向的构造函数,不能有自己的方法体
class Point {
  num x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}

关于常量构造函数和工厂构造函数的介绍:
如果你的类提供一个状态不变的对象,你可以把这些对象 定义为编译时常量。要实现这个功能,需要定义一个 const 构造函数, 并且声明所有类的变量为 final。

class ImmutablePoint {
  final num x;
  final num y;
  const ImmutablePoint(this.x, this.y);
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);
}

如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义 这个构造函数。例如,一个工厂构造函数 可能从缓存中获取一个实例并返回,或者 返回一个子类型的实例。

下面代码演示工厂构造函数 如何从缓存中返回对象。

class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to the _ in front
  // of its 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;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) {
      print(msg);
    }
  }
}

//使用 new 关键字来调用工厂构造函数。
var logger = new Logger('UI');
logger.log('Button clicked');

Method

Dart可以使用set 和get 来定义新的属性,如下:

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;
}

main() {
  var rect = new Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

操作符重载

Dart使用operator关键字 跟上要重载的操作符来定义重载方法:

class Vector {
  final int x;
  final int y;
  const Vector(this.x, this.y);

  /// Overrides + (a + b).
  Vector operator +(Vector v) {
    return new Vector(x + v.x, y + v.y);
  }

  /// Overrides - (a - b).
  Vector operator -(Vector v) {
    return new Vector(x - v.x, y - v.y);
  }
}

main() {
  final v = new Vector(2, 3);
  final w = new Vector(2, 2);

  // v == (2, 3)
  assert(v.x == 2 && v.y == 3);

  // v + w == (4, 5)
  assert((v + w).x == 4 && (v + w).y == 5);

  // v - w == (0, 1)
  assert((v - w).x == 0 && (v - w).y == 1);
}

⚠️注意:Dart中的类可以有抽象函数,而不必定义为abstract class抽象类,并且可以实例化。

⚠️注意:Dart中的每个类(枚举类型除外)都隐式的定义了一个包含所有实例成员的接口, 并且这个类实现了这个接口。如果你想 创建类 A 来支持 类 B 的 api,而不想继承 B 的实现, 则类 A 应该实现 B 的接口。
实现一个隐式接口使用implements

// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.
class Imposter implements Person {
  // We have to define this, but we don't use it.
  final _name = "";

  String greet(who) => 'Hi $who. Do you know who I am?';
}

greetBob(Person person) => person.greet('bob');

main() {
  print(greetBob(new Person('kathy')));
  print(greetBob(new Imposter()));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值