1. 程式人生 > >Dart語法快速上手三《Dart2之方法》

Dart語法快速上手三《Dart2之方法》

這裡開始講Dart語法中最重要的元素之一:方法,Dart裡面的方法跟java還是有很大的不同

方法

Dart是一種真正的面嚮物件語言,因此即使是函式也是物件並且具有型別Function。
這意味著函式可以分配給變數或作為引數傳遞給其他函式。
您也可以像呼叫函式一樣呼叫Dart類的例項。

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

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

這是一個標準的方法,其中返回型別是可以省略的,Dart會自動推斷,而它下面的那個方法則是一個方法的簡寫版

  • 可選引數和必選引數
    函式可以有兩種型別的引數:必需和可選。首先列出所需引數,然後列出任何可選引數。命名的可選引數也可以標記為@required。當我們呼叫一個方法的時候,我們可以給方法填上一個預設值,例如:
//這是一個可選引數的的方法
  optionalFunction({int a = 1 ,int b =2}){
   return a+b;
 }

//在呼叫的時候我可以選擇傳一個引數,也可以選擇不傳
main(){
optionalFunction(a:4);
optionalFunction(a:4,b:1);
optionalFunction(4,1);//TODO 錯誤!!!!
optionalFunction();
}

注意,這個方法在呼叫的時候不能像kotlin一樣通過引數的順序來指定引數,可選引數的方法傳參必須在前面加上方法的引數名,來指定引數的值
如果我在可選引數前面加上@Required註解,就表明在這一群可選引數中,這個引數是必傳項,不去傳遞這個引數是非法的

  optionalFunction({int a = 1 ,@required int b }){

   return a+b;

 }
optionalFunction(a:4);  //非法。必須傳遞b的值

注意:@Required 註解需要匯入外部包才能使用
可以直接匯入包:meta / meta.dart,也可以匯入另一個匯出meta的包,例如Flutter的包:flutter / material.dart。

  • 可選位置引數
    可選位置引數的意思就是即使你不傳入這個引數,也可以呼叫這個方法,在上面一個例子中我們發現
  optionalFunction({int a = 1 ,int b =3 }){

   return a+b;

 }

這個方法,如果呼叫的時候是這樣呼叫的

optionalFunction(4);

這樣編譯是過不了的,系統不知道你這個4是a還是b
但是可選引數中這樣呼叫是可以的,即使你這個可選引數沒有預設值,看程式碼

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

在上面這個示例中,第三個引數device在第一次呼叫中是沒有傳遞的,但是編譯器沒有報錯,這就是可選位置引數與全部可選引數的區別

級聯表示法

級聯類似於java裡面的build設計模式,可以通過單行一系列的語法操作一個物件

class Grammar2 {
  var x, y, z;
}
var g2 = Grammar2();
    g2 ..x = 1 ..y = 2..z=3;//這樣就完成了一系列的賦值
等價於
g2.x = 1; g2.y=2;g2.z=3;


  querySelector('#sample_text_id')
    ..text = 'Click me!'
    ..onClick.listen(reverseText);

Functions as first-class objects(這個感覺翻譯成中文怪怪的)

你可以傳遞一個方法當作一個引數傳遞給另一個方法

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

var list = [1, 2, 3];

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

上面這是一個簡單版本的方法傳遞,這裡延伸一下方法傳遞的概念Typedefs,java裡面是沒有方法當作引數的概念的,Dart將這個玩的很6,我們看看Typedefs

Typedefs

在Dart中,函式是物件,就像string和int一樣,typedef或為函式型別提供了在宣告欄位和返回型別時可以使用的名稱。當函式型別分配給變數時,typedef會保留型別資訊。

class SortedCollection {
  Function compare;

  SortedCollection(int f(Object a, Object b)) {
    compare = f;
  }
}

// Initial, broken implementation.
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);

  // All we know is that compare is a function,
  // but what type of function?
  assert(coll.compare is Function);
}

上面這種是普通的方法傳遞的程式碼,就跟註釋上面的疑問一樣,都知道這個傳遞進來的f是一個方法,但是是什麼型別的方法呢?
這個時候typedef就派上用場了將f分配給比較時,型別資訊會丟失。f的型別是(Object,Object)→int(其中→表示返回),但比較的型別是Function。
如果我們將程式碼更改為使用顯式名稱並保留型別資訊,則開發人員和工具都可以使用該資訊。

typedef Compare = int Function(Object a, Object b); //typedef關鍵字需要定義在class的外圍

class SortedCollection {
  Compare compare;

  SortedCollection(this.compare);
}

// Initial, broken implementation.
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);
  assert(coll.compare is Function);
  assert(coll.compare is Compare);
}

也可以增加泛型

typedef Compare<T> = int Function(T a, T b);

int sort(int a, int b) => a - b;

void main() {
  assert(sort is Compare<int>); // True!
}

方法的註解

Dart常用的有@override和@deprecated意思跟java一樣,這裡略過

####匿名方法
也稱作為無名方法,顧名思義,就是這個方法沒有方法名,其他的跟普通方法一樣。舉個例子:如果我們初始化一個值ax,這個ax的值需要從一個方法的返回值中拿到,在java裡面我們這麼做

int ax = getAx(9);
int getAx(int a){
  return a *2;
}

Dart中是這樣的
var ax = (a) => a2;
是不是簡潔了很多?那麼無名方法在哪裡呢?就是這個(a)=>a
2這個方法除了沒有名字,其他跟上面的一樣
第二個應用場景就是有些方法需要你傳遞一個方法進去,第一種辦法是上面我們例子說的,定義一個普通方法傳遞進去

int sort(Object a, Object b) {
......
}
functionPass(sort);  //普通方法

//無名的寫法是這樣的

void functionPass((Object a, Object b){
.......
})

//更加常用的地方的是
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

方法的返回值

這裡單獨提一下方法的返回值,預設情況下dart的方法不寫返回值不代表沒有返回值,他的返回值是null

foo() {}

assert(foo() == null);

未完待續~~~~~