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閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容

  • 版權聲明:本文為博主原創文章,未經博主允許不得轉載。http://www.lxweimin.com/p/44ae7...
    AWeiLoveAndroid閱讀 17,238評論 6 65
  • 此文章是v1.0+時編寫,年代久遠,小心有毒,謹慎食用!!! 一些重要概念 所有的東西都是對象,所有的對象都是類的...
    soojade閱讀 10,084評論 2 27
  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,120評論 1 32
  • 1.今日又見雪飛,卻已心如止水,甚或有些子埋怨,地凍天寒諸事不便,若不是寒雪有除蟲之益,真要生發一絲厭心。 2.以...
    chen小凱閱讀 154評論 0 0
  • 在職場當中很多地方都需要說服別人的情況,包括開會,建議,總結,演講等,面對老板,同事,開會有不同的說話技巧,當把說...
    簡單study閱讀 874評論 0 50