跨平台开发flutter

Flutter-Dart基础语法入门

2018-11-14  本文已影响193人  张叔叔

Dart语法基础

Dart语言简介

Dart是Google推出的一门编程语言,最初是希望取代Javascript运行在浏览器端,后台慢慢发展成可以开发Android、iOS和web端APP的一门高质量的编程语言,目前Dart的版本是Dart2。

Dart语言特性

Productive
Dart’s syntax is clear and concise, its tooling simple yet powerful. Sound typing helps you to identify subtle errors early. Dart has battle-hardened core libraries and an ecosystem of thousands of packages.

Fast
Dart provides optimizing ahead-of-time compilation to get predictably high performance and fast startup across mobile devices and the web.

Portable
Dart compiles to ARM and x86 code, so that Dart mobile apps can run natively on iOS, Android, and beyond. For web apps, Dart transpiles to JavaScript.

Approachable
Dart is familiar to many existing developers, thanks to its unsurprising object orientation and syntax. If you already know C++, C#, or Java, you can be productive with Dart in just a few days.

Reactive
Dart is well-suited to reactive programming, with support for managing short-lived objects—such as UI widgets—through Dart’s fast object allocation and generational garbage collector. Dart supports asynchronous programming through language features and APIs that use Future and Stream objects.

Dart语法简介

官网上对于Dart的语法也有详细介绍,不过是全英文的,如果对英文没有什么阅读障碍,可以直接移步官方文档

下面我们通过Android Studio作为开发工具来一起了解Dart的语法基础。

NewFlutterProject.png

新创建的Flutter项目,Dart代码主要在 lib/main.dart文件中,由于本篇主要讲的是Dart的语法,故暂时不看main.dart文件,在lib目录下我们创建一个新的.dart文件grammar.dart,如图:

newdartfile.png

然后我们在grammar.dart中键入以下代码

// Define a function.
printInteger(int aNumber) {
  print('The number is $aNumber.'); // Print to console.
}

// This is where the app starts executing.
main() {
  var number = 42; // Declare and initialize a variable.
  printInteger(number); // Call a function.
}

这段代码一些基本的用法,基本所有的语言都通用的语法:

// This is a comment.

单行代码注释,不用多说
int

int是Dart中的一种数据类型,同时还有其他的数据类型如:String List bool等。
42

一个数字字面量,数字字面量是编译时常量的一种。
print()

显示输出的一种便捷方法
'xxx'  或者 “xxx”

两种方式都可以表示字符串
$variableName 或者 ${expression}

字符串插值:包含一个变量或表达式的字符串等效于字符串字面量
sample:
var name = 'zgy';
print("hi,I am $name");
int a = 1,b = 2;
print("$a + $b = ${a + b}");

main()

主函数,程序从这里开始。。。
var

一种声明变量而不指定其类型的方法
示例代码中 var number = 42;  //这里42被推断为int类型

Dart重要概念

Dart变量

声明变量有多种方式:

main(){
    int a = 10;   //指明变量类型为int
    bool = true;       //指明变量类型为bool
    String name = 'zgy';  //指明变量类型为String
    var name = 'zgy';   //自动推断变量类型String
    dynamic  name = 'zgy';  //自动推断变量类型String
}

默认值

未初始化的变量的初始值为null

Final 和 const修饰符

如果您从未打算更改一个变量,请使用final或const修饰他,而不是使用var或其他变量类型。最终变量只能设置一次;const变量是一个编译时常数。(Const变量是隐式最终变量。)最终的顶级或类变量在第一次使用时被初始化。

注意:实例变量可以是final,但不能是const。[实例变量定义在对象一级,它可以被类中的任何方法或者其他类中的方法访问,但是不能被静态方法访问。]

Sample:
final name = 'zgy'; // Without a type annotation
final String nickname = 'zgy';

你无法更改final变量的值:

name = 'zgy';  //Error:a final variable can only be set once.
//这是个错误的示例,使用final声明的变量是不可以更改的。

对于想要在编译时确定并且不再变的变量,使用const。如果const变量位于类级别,则将其标记为静态const。在声明该变量时,将该值设置为编译时常量,例如数字或字符串字面量、const变量或常量数字算术运算的结果:

const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere

const关键字不只是声明常量变量。您还可以使用它来创建常量值,以及声明创建常量值的构造函数。任何变量都可以赋一个常量值。

var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`

您可以从const声明的初始化表达式中省略const,如上面的baz。

您可以更改一个非final的非const变量的值,即使它曾经有一个const值:

foo = [1, 2, 3]; // Was const []

你不能改变const变量的值:

baz = [42]; // Error: Constant variables can't be assigned a value.

Final和Const的区别:

内建类型

Dart有以下几种内建的数据类型:

下面用一段代码来演示以上各类数据类型:

main() {
  // numbers  有两种形式 int和double
  var a = 0;
  int b = 1;
  double c = 0.1;

  // strings
  var s1 = 'zgy';
  String s2 = "zgy";

  // booleans
  var real = true;
  bool isReal = false;

  // lists
  var arr = [1, 2, 3, 4, 5];
  List<String> arr2 = ['hello', 'world', "123", "456"];
  List<dynamic> arr3 = [1, true, 'zgy', 1.0];

  // maps   在Dart2中new关键字是可选的
  var map = new Map();
  map['name'] = 'zhangsan';
  map['age'] = 10;
  Map m = new Map();
  m['a'] = 'a';

  //runes,Dart 中 使用runes 来获取UTF-32字符集的字符。String的 codeUnitAt and codeUnit属性可以获取UTF-16字符集的字符
  var clapping = '\u{1f44f}';
  print(clapping); // 打印的是拍手emoji的表情

  // symbols 符号对象表示在Dart程序中声明的操作符或标识符。您可能永远不需要使用符号,但是对于按名称引用标识符的api来说,它们是非常重要的,因为缩小改变了标识符名称而不是标识符符号
  print(#s == new Symbol("s")); // true
}

函数

Dart是一种真正的面向对象语言,所以即使函数也是对象,具有类型和功能。这意味着函数可以分配给变量或作为参数传递给其他函数。您还可以像调用函数一样调用Dart类的实例。

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

//以上两个函数等价,省略类型函数仍然可以工作

对于只包含一个表达式的函数,可以使用简写语法:

// =>可以替代return
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

可选参数

可选的命名参数

在定义函数时,使用{param1, param2,…}来指定命名参数:

/// Sets the [bold] and [hidden] flags ...  
//注意花括号
void enableFlags({bool bold, bool hidden}) {...}

在调用函数时,可以使用paramName: value来指定命名参数。例如:

enableFlags(bold: true, hidden: false);

可以使用@required说明它是一个必传的参数:

const Scrollbar({Key key, @required Widget child})

可选位置参数

在[]中包装一组函数参数,标记为可选的位置参数:

String say(String from, String msg, [String device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

main(){
    print(say('Bob', 'Howdy'));
    //log: ob says Howdy
    print(say('Bob', 'Howdy', 'smoke signal'));
    //log: Bob says Howdy with a smoke signal
}

默认参数值

函数可以使用=来定义命名和位置参数的默认值。如果没有提供默认值,则默认值为null。

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

匿名函数

大多数函数都被命名,如main()或printElement()。你也可以创建一个没有函数名称的函数,这种函数称为匿名函数。

test(Function callback) {
  callback('I am zgy');
}

main(){
  test((String name){
    print('$name');
  });
}

运算符

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

  int a = 1;
  ++a;
  a++;
  var b = 1;
  print(a == b);  // false
  print(a * b); // 3
  bool real = false;
  real ? print('real') : print('not real'); // not real
  print(real && a == b); // false
  print(real || a == 3); // true
  print(a != 2); // true
  print(a <= b); // false
  var c = 9;
  c += 10;
  print("c = $c"); // c = 19
  print(1<<2); // 4

  // 与Java不太一样的运算符操作

  // is运算符用于判断一个变量是不是某个类型的数据
  // is!则是判断变量不是某个类型的数据
  var s = "hello";
  print(s is String); // true
  var num = 6;
  print(num is! String); // true

  // ~/才是取整运算符,如果使用/则是除法运算,不取整
  int k = 1;
  int j = 2;
  print(k / j); // 0.5
  print(k ~/ j); // 0

  // as运算符类似于Java中的cast操作,将一个对象强制类型转换
  (emp as Person).teach();

  // ??=运算符 如果 ??= 运算符前面的变量为null,则赋值,否则不赋值
  var param1 = "hello", param2 = null;
  param1 ??= "world";
  param2 ??= "world";
  print("param1 = $param1"); // param1 = hello
  print("param2 = $param2"); // param2 = world
  
  // ?.运算符
  var str1 = "hello world";
  var str2 = null;
  print(str1?.length); // 11
  print(str2?.length); // null 
  print(str2.length); // 报错
}

..运算符(级联操作)

class Person {
  eat() {
    print("I am eating...");
  }

  sleep() {
    print("I am sleeping...");
  }

  study() {
    print("I am studying...");
  }
}

main() {
  // 依次打印
  //  I am eating...
  //  I am sleeping...
  //  I am studying...
  new Person()..eat()
      ..sleep()
      ..study();
}

可以看出..调用某个对象的方法(或者成员变量)时,返回值是这个对象的本身,所以你可以接着使用用..调用这个对象的其他方法。

流程控制语句

您可以使用以下任何一种方法来控制Dart代码的流:

你也可以使用try-catch和throw来对控制流程作出改变。

Dart是一种面向对象的语言,具有类和基于mixin的继承。每个对象都是一个类的实例,所有的类都是Object的子类。基于mixin的继承意味着,尽管每个类(除了Object)都只有一个超类,但类主体可以在多个类层次结构中重用。

Dart中的类没有访问控制,所以你不需要使用privateprotectedpublic等修饰成员变量或成员函数,一个简单的类如下代码所示:

class Person {
    String name;
    int age;
    String gender;
    //类同名的构造方法
    Person(this.name, this.age, this.gender);
    //Person.init(){    类的命名构造方法
    //    name = 'baby';
    //    age = 1;
    //}
    sayHello() {
        print("hello,my name is $name,I am $age years old, I am $gender");
    }   
}

上面的Person类中有3个成员变量,一个构造方法和一个成员方法,看起来比较奇怪的是Person的构造方法,里面传入的3个参数都是this.xxx,而且没有大括号{}包裹的方法体,这种语法是Dart比较独特而简洁的构造方法声明方式,它等同于下面的代码:

Person(String name, int age, String gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}

使用类成员

使用点号(.)引用实例变量或方法:

main (){
    var p = Person("zhang", 10,"male");
    p.sayHello();  
    p.age = 20;
    p.name = 'lisi';
    p.sayHello(); 
} 

为避免最左操作数为空时出现异常,使用 ?.代替 .来使用:

// If p is non-null, set its y value to 4.
p?.y = 4;

类的继承

Dart中使用extends关键字做类的继承,如果一个类只有命名的构造方法,在继承时需要注意,如下代码:

class Student extents Person{
    Student.init() : super.init(){
        //
    }
}

类的成员方法

一个类的成员方法是一个函数,为这个类提供某些行为。上面的代码中已经有了一些类的成员方法的定义,这些定义方式跟Java很类似,你可以为某个类的成员变量提供getter/setter方法,如下代码:

class Rectangle {
  num left, top, width, height;

  // 构造方法传入left, top, width, height几个参数
  Rectangle(this.left, this.top, this.width, this.height);

  // right, bottom两个成员变量提供getter/setter方法
  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

抽象类和抽象方法

使用abstract修饰一个类,则这个类是抽象类,抽象类中可以有抽象方法和非抽象方法,抽象方法没有方法体,需要子类去实现,如下代码:

abstract class Doer {
  // 抽象方法,没有方法体,需要子类去实现
  void doSomething();
  // 普通的方法
  void greet() {
    print("hello world!");
  }
}

class EffectiveDoer extends Doer {
  // 实现了父类的抽象方法
  void doSomething() {
    print("I'm doing something...");
  }
}

枚举类

使用 enum关键字定义一个枚举类

enum frame {x, y, width, height}

mixins

mixins是一个重复使用类中代码的方式,比如下面的代码:

class A {
  a() {
    print("A's a()");
  }
}

class B {
  b() {
    print("B's b()");
  }
}

// 使用with关键字,表示类C是由类A和类B混合而构成
class C = A with B;

main() {
  C c = new C();
  c.a(); // A's a()
  c.b(); // B's b()
}

静态成员变量和静态成员方法

使用static关键字修饰类的成员变量和成员方法

泛型

泛型通常是类型安全所必需的,他们对于写出严谨高质量的代码是很有用的:

使用库

使用import来指定如何在另一个库的范围中使用来自一个库的命名空间。例如,Dart web应用程序通常使用Dart:html库,它们可以这样导入:

import 'dart:html';

导入一个库仅仅需要提供库的URI。对于内置库,URI具有特定的形式(dart:scheme)。对于其他库,可以使用文件路径或者包:scheme的形式。包:scheme形式指定包管理器(如pub工具)提供的库。例如:

import 'package:test/test.dart';

注意:URI表示统一资源标识符。url(统一资源定位器)是一种常见的URI

指定一个库前缀

如果您导入两个具有冲突标识符的库,那么您可以为一个或两个库指定一个前缀。例如,如果library1和library2都有一个Element类,那么你可以用以下的方法:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Uses Element from lib1.
Element element1 = Element();

// Uses Element from lib2.
lib2.Element element2 = lib2.Element();

只导入库的一部分

// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;

懒加载库

延迟加载(也称为懒加载)允许应用程序在需要时按需加载库。以下是一些您可能使用延迟加载的情况:

要延迟加载库,必须首先使用deferred as进行导入。

import 'package:greetings/hello.dart' deferred as hello;

当您需要库时,使用库的标识符调用loadLibrary()。

Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

部分源码参考:yubo_725Dart2中文文档

上一篇下一篇

猜你喜欢

热点阅读