Flutter小白教程系列(三) --- Dart语言快速入门

##转载请注明出处: learnandfish.com/html

入门简单的Dart程序

// 定义一个函数
printNumber(int number) {
  print('The number is $number.'); // 打印到控制台。
}

// 入口函数
void main() {
  var number = 42; // 声明并初始化一个变量。
  printNumber(number); // 调用函数。
}
复制代码
  • // 代码注释。
  • $variableName (或 ${expression}) 获取变量值

重要概念

在学习 Dart 语言时, 应该基于如下事实和概念:express

  • 万物皆对象, 不管是数字,函数和null都是对象。全部对象继承自Object类。
  • 尽管Dart语言是强类型的, 可是Dart能够推断类型, 上面的var number等价于int number。
  • 针对于不肯定的数据类型,请使用dynamic。
  • Dart支持泛型, 如List(整数列表)和List(任何类型的对象列表)。
  • 与Java不一样, Dart中没有权限关键字"public", "protected", "private"。 若是标识符如下划线(_number)开头, 则认为是私有属性。
  • Dart语言定义的变量,若是不赋值,默认为空null。

变量

Dart内建数据类型以下:编程

  • Number 经过num声明
  • int 整数值
  • double 双精度浮点值
void main() {
  var number = 1; // Dart会自动推断为int类型
  int value = 1; // 显示声明为int类型
  print(number == value); // 该值应为true, 由于上述两个变量的值和类型相同

  var pointNumber = 1.0; // Dart会自动推断为double类型
  double pointValue = 1.0; // 显示声明为double类型
  double pointValueCast = 1; // Dart2.1以后会自动转换为为double类型
  print(pointNumber == pointValue); // 该值应为true, 由于上述两个变量的值和类型相同
  print(pointNumber == pointValueCast); // 该值应为true, 由于上述两个变量的值和类型相同
}
复制代码
  • String
  • 以单引号或者双引号包裹。
  • 能够经过"+"链接。
  • 能够经过$variableName或者${expression}获取取值。
  • 使用r前缀建立原始字符串。
  • 对象的经常使用方法请查阅String经常使用方法
void main() {
  var s1 = "我是字符串1";
  String s2 = "我是字符串2";
  // s3虽然手动换行,可是输出的时候仍是在一行
  var s3 = '我是'
      '字符串'
      '3';
  // s4和s5为多行字符串
  var s4 = """ 我是 字符串 4 哈哈哈 """;
  var s5 = ''' 我是 字符串 4 哈哈哈 ''';
  // s6会换行
  var s6 = "In a raw string, even \n isn't special.";
  // s7保持原样输出
  var s7 = r"In a raw string, even \n isn't special.";
  print(s1);
  print(s2);
  print(s3);
  print(s4);
  print(s5);
  print(s6);
  print(s7);
}

/* console 我是字符串1 我是字符串2 我是字符串3 我是 字符串 4 哈哈哈 我是 字符串 4 哈哈哈 In a raw string, even isn't special. In a raw string, even \n isn't special. */
复制代码
  • Boolean
  • Dart 使用 bool 类型表示布尔值。 Dart 只有字面量 true and false 是布尔类型, 这两个对象都是编译时常量。
void main() {
  var b = true;
  var c = false;
  bool d; // 声明变量不赋值的状况下,默认为null
  bool e  = true;
  print(b);
  print(c);
  print(d);
  print(e);
}
/* console true false null true */
复制代码
  • List
  • 几乎每种编程语言中最多见的集合多是array或有序的对象集合。在Dart中的Array就是List对象, 一般称之为List。
void main() {
  var list = [1, 2, 3];
  List list1 = [1, 2, 3];
  assert(list.length == 3);
  assert(list[1] == 2);

  list[1] = 1;
  assert(list[1] == 1);
}
复制代码
  • Set
  • 在Dart中Set是一个元素惟一且无序的集合。
void main() {
  var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
  // Dart 推断 halogens 类型为 Set<String> 。若是尝试为它添加一个 错误类型的值,分析器或执行时会抛出错误。
  halogens.add('haha'); // 添加成功
// halogens.add(1); // 类型错误,编译时提示
 // 要建立一个空集,使用前面带有类型参数的 {} ,或者将 {} 赋值给 Set 类型的变量
  var names = <String>{};
  Set<String> names1 = {}; // 这样也是能够的。
// var names = {}; // 这样会建立一个 Map ,而不是 Set 。
  var elements = <String>{};
  // 使用 add() 或 addAll() 为已有的 Set 添加元素
  elements.add('fluorine');
  elements.addAll(halogens);
  // 使用 .length 来获取 Set 中元素的个数
  assert(elements.length == 5);
}
复制代码
  • Map
  • Map是用来关联keys和values的对象。keys和values能够是任何类型的对象。
  • 在一个Map对象中一个key只能出现一次。可是value能够出现屡次。
void main() {
  var gifts = {
    // Key: Value
    'first': 'partridge',
    'second': 'turtledoves',
    'fifth': 'golden rings'
  };

  var nobleGases = {
    2: 'helium',
    10: 'neon',
    18: 'argon',
  };
  // 以上 Map 对象也可使用 Map 构造函数建立
  var gifts1 = Map();
  gifts['first'] = 'partridge';
  gifts['second'] = 'turtledoves';
  gifts['fifth'] = 'golden rings';

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

  // 赋值
  gifts['fourth'] = 'calling birds';
  // 从一个 Map 中获取一个 value
  var first = gifts['first'];
  // 获取Map的长度
  print(gifts.length);
}
复制代码
  • Rune和Symbol
  • 不经常使用,有兴趣能够自行学习。
  • 经过Symbol声明的变量, 经过#variableName调用

final和const

  • 使用过程当中历来不会被修改的变量, 可使用final或const, 而不是var或者其余类型。
  • final变量的值只能被设置一次; const变量在编译时就已经固定(const变量是隐式final类型)。
void main() {
  final name = 'Bob';
  final String nickname = 'Bobby';
// name = 'Jack'; // Error: 一个 final 变量只能被设置一次。
  // const是编译时就固定值
  const bar = 1000000; // 压力单位 (dynes/cm2)
  const double atm = 1.01325 * bar; // 标准气压
  // Const 关键字不只能够用于声明常量变量。 还能够用来建立常量值。
  var foo = const []; // 等价于 var foo = [];
  final bar1 = const [];
  const baz = []; // Equivalent to `const []`
  // 非 Final , 非 const 的变量是能够被修改的,即便这些变量 曾经引用过 const 值。
  foo = [1, 2, 3]; // 曾经引用过 const [] 常量值。
  // final和const修饰的不能修改
// bar1 = [1]; // 编译时报错, final修饰的不可修改
// baz = [2]; // 编译时报错, const修饰的不可修改
}
复制代码

函数

  • Dart 是一门真正面向对象的语言, 甚至其中的函数也是对象, 而且有它的类型Function。
  • 这也意味着函数能够被赋值给变量或者做为参数传递给其余函数。也能够把Dart类的实例当作方法来调用。
// 有返回值的函数
bool showPrice() {
   return true;
}

// 返回值为void
void printVoidNumber() {
  print('return void');
}

// 返回值为void, 此时void的能够省略
printVoidNumber1() {
  print('return void');
}

// 若是一个函数函数体只有一行,能够用箭头代替大括号
// => expr 语法是 { return expr; } 的简写。 => 符号 有时也被称为 箭头 语法。
showBooleanValue() => true;

// 将函数赋值给一个变量
var a = showBooleanValue();


void main() {
  print(a);
}

复制代码
  • 可选参数
  • 命名可选参数, 放在大括号内{}
void enableFlags({bool bold, bool hidden}) {}
复制代码
  • 位置可选参数, 放在中括号内[]
String say(String from, String msg, [String device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

// 方法调用
void main() {
  say('Bob', 'Howdy'); //不使用可选参数
  say('Bob', 'Howdy', 'smoke signal'); //使用可选参数
}
复制代码
  • 默认参数值
/// 设置 [bold] 和 [hidden] 标志 ...
void enableFlags({bool bold = false, bool hidden = false}) {}

void main(){
  // bold 值为 true; hidden 值为 false.
  enableFlags(bold: true);
}
复制代码
  • 函数是一等公民
  • 一个函数能够做为另外一个函数的参数。
  • 一样能够将一个函数赋值给一个变量。
printElement(int element) => print(element);

void mian(){
  var list = [1, 2, 3];
  
  // 将 printElement 函数做为参数传递。
  list.forEach(printElement);
}
复制代码
  • 匿名函数
void main() {
  var list = ['apples', 'bananas', 'oranges'];
  list.forEach((item) {
    print('${list.indexOf(item)}: $item');
  });
}
复制代码
  • 闭包:其实闭包就是在一个函数中能够调用其余的函数,这样其余的函数可使用本函数的参数及其余内容。

运算符

  • 类型判断运算符
  • as 类型转换
  • is 判断是否为某类型
  • is! 判断不是某类型
  • 赋值运算符
  • a = value; 将value赋值给便里昂a
  • b ??= value; 若是b为空时, 将value赋值给b, 不然b的值保持不变。
  • 条件表达式
  • condition ? expr1 : expr2 若是条件为 true, 执行 expr1 (并返回它的值): 不然, 执行并返回 expr2 的值。
  • expr1 ?? expr2 若是 expr1 是 non-null, 返回 expr1 的值; 不然, 执行并返回 expr2 的值。
  • 级联运算符
  • 能够实现对同一个对象进行一系列的操做。
  • 除了调用函数, 还能够访问同一对象上的字段属性。这一般能够节省建立临时变量的步骤, 同时编写出更流畅的代码。
  • 相似与build模式。
class Person{
  int age;
  String name;
  
  Person({this.name, this.age});
  
  void say(String words) {
    print(name + words);
  }
}
void main(){
  Person() // 获取对象。
    ..name = 'Bob' // 调用成员变量。
    ..say('important');
  // 等价于下面的代码
  var person = Person(name: "Bob");
  person.say('important');
  // 级联运算符能够嵌套
  /*final addressBook = (AddressBookBuilder() ..name = 'jenny' ..email = 'jenny@example.com' ..phone = (PhoneNumberBuilder() ..number = '415-555-0100' ..label = 'home') .build()) .build();*/
  // 在返回值为void的函数以后不能继续调用级联操做符
  var sb = StringBuffer();
  sb.write('foo') // write函数返回值是void, 不能再继续调用
    ..write('bar');  // 运行会报错
}
复制代码

控制流程语句

// if elseif else
weatherStatus(){
  if (isRaining()) {
    you.bringRainCoat();
  } else if (isSnowing()) {
    you.wearJacket();
  } else {
    car.putTopDown();
  }
}

// for 循环
text(){
  var message = StringBuffer('Dart is fun');
  for (var i = 0; i < 5; i++) {
    message.write('---$i!');
  }
  // for ... in ...
  var collection = [0, 1, 2];
  for (var x in collection) {
    print(x); // 0 1 2
  }
  // forEach
  collection.forEach((item) => print(item));
}

// while 和 do-while
printSomethings() {
  while (!isDone()) {
    doSomething();
  }
  do {
    printLine();
  } while (!atEndOfPage());
}

// break 和 continue
pauseSomethings(){
  while (true) {
    if (shutDownRequested()) break;
    processIncomingRequests();
  }
  // 执行yearsExperience大于等于5的元素
  for (int i = 0; i < candidates.length; i++) {
    var candidate = candidates[i];
    if (candidate.yearsExperience < 5) {
      continue;
    }
    candidate.interview();
  }
  // 若是candidate对象实现了Iterable接口, 能够调用以下方式
  candidates
      .where((c) => c.yearsExperience >= 5)
      .forEach((c) => c.interview());
}

// switch 和 case
judgeType() {
  var command = 'OPEN';
  switch (command) {
    case 'CLOSED':
      executeClosed();
      break;
    case 'PENDING':
      executePending();
      break;
    case 'APPROVED':
      executeApproved();
      break;
    case 'DENIED': // 当command为该种状况时,因为该分支没有break语句会继续执行下一个分支,直到遇到break中止执行。
      executeDenied();
    case 'OPEN':
      executeOpen();
      break;
    default:
      executeUnknown();
  }
}
// assert 判断是否成立
judgeEquals() {
  // 确认变量值不为空。
  assert(text != null);
  
  // 确认变量值小于100。
  assert(number < 100);
  
  // 确认 URL 是不是 https 类型。
  assert(urlString.startsWith('https'));
  // assert 的第二个参数能够为其添加一个字符串消息。
  assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".');
}
复制代码

异常处理

  • Dart 代码能够抛出和捕获异常。
  • 异常表示一些未知的错误状况。若是异常没有被捕获, 则异常会抛出, 致使抛出异常的代码终止执行。
  • throw 能够抛出Dart定义的异常, 也能够抛出任意对象
// 高质量的生产环境代码一般会实现 Error 或 Exception 类型的异常抛出。
throw FormatException('Expected at least 1 section');
throw 'Out of llamas!';
// 完整的try catch finally代码
try {
  // 代码块
} on Exception catch (e) {
  // 捕获到异常走这里
} finally {
  // 不管是否捕获异常, 最终都会走这里
}
复制代码

类和构造函数

  • 经过class关键字声明。
  • 在没有声明构造函数的状况下, Dart会提供一个默认的构造函数。默认构造函数没有参数并会调用父类的无参构造函数。
class Point {
  num x, y;

  // 构造函数的第一种方法
  Point(num x, num y) {
    // 还有更好的方式来实现下面代码,敬请关注。
    this.x = x;
    this.y = y;
  }
  
  // 构造函数的第二种方法
  Point(this.x, this.y)
  
  // 构造函数的第三种方法--命名构造函数
  Point.origin(){
    x = 0;
    y = 0;
  }
}
复制代码
  • 类的继承
  • 子类经过关键字extends继承父类。
  • 默认状况下, 子类的构造函数会自动调用父类的默认构造函数(匿名, 无参数)。
  • 若是父类没有匿名无参的构造函数, 则在子类中须要手动调用父类的构造函数。
class Person {
  String firstName;
  
  Person.fromJson(Map data){
    print("I'm $firstName");
  }
}

class Employee extends Person {
  
  Employee.fromJson(Map data) : super.fromJson(data){
    print("I'm Employee");
  }
  
}

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

  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}
复制代码
  • 构造函数不只能够调用父类构造函数, 还能够在构造函数体执行以前初始化成员变量。
import 'dart:math';

class Point {
  final num x;
  final num y;
  final num distance;

  Point(x, y)
      : x = x,
        y = y,
        distance = sqrt(x * x + y * y);
}
复制代码
  • 重定向构造函数
class Point {
  num x, y;

  // 类的主构造函数。
  Point(this.x, this.y);

  // 指向主构造函数
  Point.alongXAxis(num x) : this(x, 0);
}
复制代码
  • 常量构造函数
  • 若是该类生成的对象是固定不变的, 那么就能够把这些对象定义为编译时常量。
  • 为此须要定义一个const构造函数, 而且声明全部实例变量为final。
class ImmutablePoint {
  static final ImmutablePoint instance =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}
复制代码
  • 工厂构造函数
  • 当执行构造函数并不老是建立这个类的一个新实例时, 则使用 factory 关键字。
  • 一个工厂构造函数可能返回一个cache中的实例。
class Logger {
  final String name;
  bool mute = false;

  // 从命名的 _ 能够知,
  // _cache 是私有属性。
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  // 私有命名构造函数 
  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}
复制代码
  • Getter 和 Setter方法
class Person {
  num age;
  final String name;
  final String hobby;
  
  // Getter
  String get hobby => "basketball";
  // Setter
  set hobby(String hobbyName) => hobby = hobbyName;
  
  Person(this.name, this.age)
}
复制代码
  • abstract 和 implements
  • abstract抽象类, 类中的抽象方法经过分号结束, 不用实现函数体, 故能够省略大括号。
  • implements实现接口。每一个类都隐式的定义了一个接口, 接口包含该类全部的成员及其实现的接口。
// 抽象类
abstract class Person {
    void walk(); // 抽象方法
}

class Animal { 
  void fly() => print("I can fly");
}

class Bird implements Animal {
  void fly() {
    // 具体实现
  }
}
复制代码
  • 重写运算符 经过operator重写
class Vector {
  final int x, y;

  Vector(this.x, this.y);
  
  // 返回值 operator 运算符(参数) {具体实现}
  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

}
复制代码
  • noSuchMethod()
  • 当代码尝试调用类中不存在的方法时, 会抛出NoSuchMethodError异常, 能够经过重写该方法实现本身想要的结果。
class Animal {
  
  @override
  void noSuchMethod(Invocation invocation){
    // 具体实现
  }
}
复制代码
  • 枚举类型
enum Color {
  RED, GREEN, BLUE
}
复制代码
  • Mixin为类添加新功能
  • Mixin是复用类代码的一种途径, 复用的类能够不存在继承关系。
  • 经过with后面跟一个或者多个类进行复用。
  • 经过mixin定义一个Mixin类, Mixin类经过on复用其余类
class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

mixin MusicalPerformer on Musician {}
复制代码
  • 静态变量和静态类型
class Animal {
  
  static const height = 180;
  
  static num distance(){
    return 100;
  }
  
}
复制代码

// 经过import导入
import 'dart:html';
// 经过as指定别名, 调用时经过lib2调用
import 'package:lib2/lib2.dart' as lib2;
// 导入库的一部分, 减小包体积
// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
// 延迟加载库, 当使用时进行加载
import 'package:greetings/hello.dart' deferred as hello;

Future greet() async {
  // 使用时使用loadLibrary()加载
  await hello.loadLibrary();
     hello.printGreeting();
   }
复制代码

异步(Future和Stream)

  • Future 使用async 和 await 构造。
Future<bool> downLoad(String url) async {
  val result = await down();
  return result;
}
复制代码
  • Stream可以屡次响应事件, 好比下载进度回调经常使用。
  • 有个博客介绍的比较详细, 请查看Future使用Stream介绍

typedefs

  • 为函数定义别名
typedefs Compare<T> = int Function(T a, T b);
复制代码

注释

// 单行注释

/* 多行注释 多行注释 多行注释 */

/// 文档注释
/// 文档注释

/** * 文档注释 */
复制代码

若是你以为本篇博客对你有用,能够点个赞,评个论或者打个赏给博主增长动力哦。markdown

相关文章
相关标签/搜索