Flutter-Dart基础语法入门

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重要概念

  • 一切皆对象,无论数字、函数、和null都是对象。所有对象都继承自[Object]类。

  • Dart是强类型语言,但是类型声明可选,因为Dart可以推断类型。(类似Swift)

  • Dart支持通用类型,如List<int>(整数列表)或List<dynamic>(任何类型的对象列表)。

  • Dart支持顶级函数(如main()),以及绑定到类或对象(分别是静态方法(static)和实例(instance)方法)的函数。您还可以在函数(嵌套或局部函数)中创建函数。

  • 类似地,Dart支持顶级变量,以及绑定到类或对象(静态和实例变量)的变量。实例变量有时被称为字段或属性。

  • 与Java不同,Dart没有公开、保护和私有的关键字。如果标识符以下划线(_)开头,则该标识符对其库是私有的。有关详细信息,请参见[库和可见性]。

  • 标识符可以以字母或下划线(_)开头,然后是这些字符加上数字的任何组合。

  • 有时候,某事物是一个表达(expression )还是一个语句(statement)是很重要的,所以这两个词要准确。

  • 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的区别:

  • 区别一:final 要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而 const 要求在声明时初始化,并且赋值必需为编译时常量。
  • 区别二:final 是惰性初始化,即在运行时第一次使用前才初始化。而 const 是在编译时就确定值了。

内建类型

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

  • numbers
  • strings
  • booleans
  • lists (also known as arrays)
  • maps
  • runes (for expressing Unicode characters in a string)
  • symbols

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

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代码的流:

  • if 和 else
  • for循环
  • while和do-while循环
  • break和continue
  • switch和case
  • assert

你也可以使用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关键字修饰类的成员变量和成员方法

泛型

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

  • 适当地指定泛型类型可以生成更好的代码。

  • var names = List<String>();
    names.addAll(['Seth', 'Kathy', 'Lars']);
    names.add(42); // Error
    
  • 您可以使用泛型来减少代码重复。

  • //T是替代类型。它是一个占位符
    abstract class Cache<T> {  
      T getByKey(String key);
      void setByKey(String key, T value);
    }
    

使用库

使用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;

懒加载库

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

  • 减少应用程序的初始启动时间。
  • 例如,要执行A/B测试——尝试算法的其他实现。
  • 加载很少使用的功能,如可选屏幕和对话框。

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

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

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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。https://www.jianshu.com/p/44ae7...
    AWeiLoveAndroid阅读 16,841评论 6 64
  • 此文章是v1.0+时编写,年代久远,小心有毒,谨慎食用!!! 一些重要概念 所有的东西都是对象,所有的对象都是类的...
    soojade阅读 10,001评论 2 27
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,034评论 1 32
  • 1.今日又见雪飞,却已心如止水,甚或有些子埋怨,地冻天寒诸事不便,若不是寒雪有除虫之益,真要生发一丝厌心。 2.以...
    chen小凯阅读 145评论 0 0
  • 在职场当中很多地方都需要说服别人的情况,包括开会,建议,总结,演讲等,面对老板,同事,开会有不同的说话技巧,当把说...
    简单study阅读 845评论 0 50