Dart基础知识-关于函数你需要知道的一切

118 阅读3分钟

前言

Dart是面向对象的编程语言,这里函数也可以对象,并且有自己的类型,Function. Function可以作为参数也可以作为返回值。

我们声明一个函数的方式

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

我们可以忽略返回值,因为编译器可以推断返回值

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

如果函数体里面只有一行代码,我们可以使用箭头表达式,如下:

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

关于参数

函数可以传递参数,这里有两种参数可以使用,一种是命名参数,另外一种是可选位置参数.

命名参数

命名参数我们可以定义为必须和非必需,区别就是是否使用required标记。当定义一个可选的命名参数如果没有

required标记,并且没有提供默认的值,我们必须要标记该参数为可Null类型。

void enableFlags({bool? bold, bool? hidden}) {...}

在调用该函数时候我们可以指定赋值参数的名字,例如

enableFlags(bold: true, hidden: false);

我们可以提供默认值给参数

void enableFlags({bool bold = false, bool hidden = false}) {...}

在调用方法时候,因为有了默认值,我们不指定参数的值也是可以的

void enableFlags({bool bold = false, bool hidden = false}) {...}

enableFlags(bold: true);

之前有提到过一个required关键字,用于指定必须要提供的参数

const Scrollbar({super.key, required Widget child});

这种情况下调用Scrollbar必须要传child,否则编译器会报错.

required标记的参数也可以为nullable.

const Scrollbar({super.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;
}

这里我们调用该方法可以不需要传第三个参数device.

assert(say('Bob', 'Howdy') == 'Bob says Howdy');

也可以传第三个参数

assert(say('Bob', 'Howdy', 'smoke signal') ==
    'Bob says Howdy with a smoke signal');

我们也可以给device赋默认值

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

assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');

这里要注意的是默认值必须要是常量.

函数作为对象

函数可以作为对象进行传参

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

var list = [1, 2, 3];

// printElement作为一个参数传递给forEach.
list.forEach(printElement);

你也可以赋值一个函数给一个变量.

var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');

匿名函数

通常函数都会有名字,不过没有函数名字的函数称为匿名函数,大致格式如下

([[*Type*] *param1*[, …]]) {  
  *codeBlock*;  
};

这里,我们也能定义参数和返回值。

const list = ['apples', 'bananas', 'oranges'];
list.map((item) {
  return item.toUpperCase();
}).forEach((item) {
  print('$item: ${item.length}');
});

在map和forEach函数中传入的都称为匿名函数,如果函数体里面只有一行代码我们可以使用箭头操作符简化操作

list
    .map((item) => item.toUpperCase())
    .forEach((item) => print('$item: ${item.length}'));

词法范围

变量的作用返回都在大括号的范围内,自内向外访问,不能外层访问内层的变量。

bool topLevel = true;

void main() {
  var insideMain = true;

  void myFunction() {
    var insideFunction = true;

    void nestedFunction() {
      var insideNestedFunction = true;

      assert(topLevel);
      assert(insideMain);
      assert(insideFunction);
      assert(insideNestedFunction);
    }
  }
}

例如myFunction是不能访问insideNestedFunction,因为insideNestedFunction在nestedFunction中声明。

函数的返回值

函数的返回值可以隐式推断,例如

foo() {}

assert(foo() == null);

foo 并没有声名返回值,但是编译器推断它返回null.