3.Functions-函数,Dart中文文档

  • 初次翻译,部分内容并非按字面翻译,是按本人理解进行了内容重组。如有错误望指正。

Dart是完全的面向对象的语言,甚至函数也是一个Function类型的对象。这意味着函数可以赋值给变量或者作为函数的参数。你可以直接用变量名(其实现了Function类)作为函数名直接调用。

参考如下示例代码:

/*如果类实现了call方法,它可以当成Function直接调用*/
class WannabeFunction {
  call(String a, String b, String c) => '$a $b $c!';
}

main() {
  var wf = new WannabeFunction();
  var out = wf("Hi","there,","gang");
  print('$out');

下面是一个函数写法的示例:

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

尽管Dart要求public的API需要说明返回类型,但是未明确指定返回类型的函数也是可以正常运行的

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

For functions that contain just one expression, you can use a shorthand syntax:

如果函数体只包含一条语句的代码块,你可以用如下简略写法:

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
The => expr syntax is a shorthand for { return expr; }. The => notation is sometimes referred to as arrow syntax.

注意:必须是一条语句的代码块,可以放在=>和;之间。

函数由两种参数类型:必须和可选。一般必须参数写在前面,可选参数紧随其后。

Optional parameters 可选参数

可选参数定义方式是位置型和命名型两种二选一。

可选命名参数定义时,你可以指定参数名和参数默认值,如下所示:

enableFlags(bold: true, hidden: false);

当定义函数时,也可以用{param1, param2, …} 来描述命名参数。如下所示:

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}

Flutter的对象初始化方法入参是复合型的,所以组件可以用命名参数的写法准确映射到各个字段。

你可以对命名参数添加@required,那么它就变为一个必须参数。

const Scrollbar({Key key, @required Widget child})
When a Scrollbar is constructed, the analyzer reports an issue when the child argument is absent.

@required在meta的包中定义,使用时,需要引入import package:meta/meta,获取其它包,其中包含了export meta的定义。

Optional positional parameters 可选位置参数

在[]中定义的参数被称为位置型参数。

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

Default parameter values 参数默认值

你可以用=给命名参数或者位置参数赋默认值。其中,默认值必须是常量。如果参数没有定义默认值,其默认为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);

废弃特性:旧的代码默认值用:做赋值,原因是命名参数只能用:赋值,现在该支持已被删除,请使用=做参数默认值赋值

下面是位置型参数定义默认值的例子:

String say(String from, String msg,
    [String device = 'carrier pigeon', String mood]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  if (mood != null) {
    result = '$result (in a $mood mood)';
  }
  return result;
}
assert(say('Bob', 'Howdy') ==
    'Bob says Howdy with a carrier pigeon');

你也可以给默认值赋值lists或者maps,下面就是这样的例子:

void doStuff(
    {List<int> list = const [1, 2, 3],
    Map<String, String> gifts = const {
      'first': 'paper',
      'second': 'cotton',
      'third': 'leather'
    }}) {
  print('list:  $list');
  print('gifts: $gifts');
}

The main() function 主函数

每个应用都会有主函数,作为程序运行的入口。main函数就是Dart的主函数,它的返回值是void,入参是一个字符串数组。

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

注意:..是对象的链式调用的写法。

下面是一个带有参数的main函数:

// Run the app like this: dart args.dart 1 test
void main(List<String> arguments) {
  print(arguments);

  assert(arguments.length == 2);
  assert(int.parse(arguments[0]) == 1);
  assert(arguments[1] == 'test');
}

你可以用args库来解析命令行参数。

Functions as first-class objects 函数型参数

你可以使用函数作为一个入参传递给另一个函数。如下面例子:

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

var list = [1, 2, 3];

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

你可以函数定义为变量,如下面所示:

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

Anonymous functions 匿名函数

大部分函数都有函数名,比如main(),printElement(),你也可以定义一个无函数名的函数,可用lambda或者closure写法,我们称之为匿名函数。同时可以将匿名函数赋予一个变量来调用。匿名函数和命名函数一样,都可以有0个或者更多的入参。如下示例所示:


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

下面是一个具体示例:

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

如果函数体只是一个语句的代码块,你可以如下简化,去除{}.

list.forEach(
    (item) => print('${list.indexOf(item)}: $item'));

Lexical scope 词汇作用域

Dart是一个lexically scoped language,意思是变量的作用域是和变量所以的代码块有关系,在变量所在代码块中,可以访问到变量。

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

Lexical closures 词汇闭包

A closure is a function object that has access to variables in its lexical scope, even when the function is used outside of its original scope.

Functions can close over variables defined in surrounding scopes. In the following example, makeAdder() captures the variable addBy. Wherever the returned function goes, it remembers addBy.

/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

void main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}

Testing functions for equality 测试函数的相等性

下面是函数的顶层函数,静态方法,对象方法的相等性

void foo() {} // A top-level function

class A {
  static void bar() {} // A static method
  void baz() {} // An instance method
}

void main() {
  var x;

  // Comparing top-level functions.
  x = foo;
  assert(foo == x);

  // Comparing static methods.
  x = A.bar;
  assert(A.bar == x);

  // Comparing instance methods.
  var v = A(); // Instance #1 of A
  var w = A(); // Instance #2 of A
  var y = w;
  x = w.baz;

  // These closures refer to the same instance (#2),
  // so they're equal.
  assert(y.baz == x);

  // These closures refer to different instances,
  // so they're unequal.
  assert(v.baz != w.baz);
}

Return values 返回值

所有函数都有返回值,如果没有特别约定,返回值为null.这是编译时,内置追加到函数体中。


foo() {}

assert(foo() == null);
  • 第四篇准备翻译 Operators操作符