掌握Flutter:Dart编程技巧

发表时间: 2022-08-07 17:49

介绍

Dart是一种完全面向对象的语言,即使函数也是对象,也有类型。这意味着函数可以被赋值给变量或作为参数传递给其他函数。

下面是一个实现方法的实例:

int add(int a, int b) {  return a + b;}

对于只包含一个表达式的函数,可以使用简写语法:

int add(int a, int b) => a + b;

=> expr 的语法是 { return expr; }, =>语法有时被称为箭头语法。

参数

一个方法可以有任意数量参数,后面可以跟着命名参数,也可以跟着可选参数(但不能两者都跟着)

  • 命名参数

定义函数时,使用{param1, param2,…}来指定命名参数。

命名参数是可选的,除非它们被显式地标记为required。

//定义void enableFlags({bool? bold, bool? hidden}) {...}//调用enableFlags(bold: true, hidden: false);

虽然命名参数是一种可选参数,但是可以用required注释它们,以表明该参数是强制性的—用户必须为该参数提供一个值。例如

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

如果有人试图在没有指定child参数的情况下创建Scrollbar,那么分析器将报错。

  • 可选参数

在[]中包装一组函数参数将它们标记为可选参数,如下:

//定义一个函数方法,同时定义device是可选的参数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');//设置device参数assert(say('Bob', 'Howdy', 'smoke signal') ==    'Bob says Howdy with a smoke signal');
  • 参数默认值

函数可以使用=为可选参数定义默认值,包括命名参数和位置参数。默认值必须是编译时常量,如果参数没有设置默认值,则默认为null。

下面是一个为命名参数设置默认值的示例:

/// 定义函数方法,并为bold和hidden设置默认值void enableFlags({bool bold = false, bool hidden = false}) {...}// 调用函数,bold = true; hidden=false.enableFlags(bold: true);

下面的例子展示了如何为位置参数设置默认值:

String say(String from, String msg, [String device = 'Android']) {  var result = '$from says $msg with a $device';  return result;}assert(say('Bob', 'Hello') == 'Bob says Hello with a Android');

还可以将List或Map作为默认值传递。下面的示例定义了一个函数doStuff(),它为list形参指定了一个默认List,并为gifts形参指定了一个默认Map:

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

Main()方法

每个应用程序必须有一个顶级的main()函数,它作为应用程序的入口点。main()函数返回void,并有一个可选的List<String>参数作为参数。如下:

void main() {  print('Hello, World!');}

接受参数的main函数:

void main(List<String> arguments) {  print(arguments);  assert(arguments.length == 2);  assert(int.parse(arguments[0]) == 1);  assert(arguments[1] == 'test');}

函数参数

函数是Dart头等对象。

可以将一个函数作为参数传递给另一个函数。例如:

void printElement(int element) {  print(element);}var list = [1, 2, 3];//将printElement做为一个参数传递.list.forEach(printElement);

还可以将函数赋值给变量,例如

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

匿名函数

大多数函数都是命名的,比如main()或上面定义的printElement()。还可以创建一个称为匿名函数的匿名函数,有时也可以创建lambda或闭包。可以将匿名函数赋给一个变量。

匿名函数看起来类似于命名函数——圆括号中有0个或多个参数,由逗号和可选类型分隔。

下面的代码块包含函数体:

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

下面的示例定义了一个匿名函数,其参数为未指定具体类型的item。对列表中的每一项调用该函数,将打印一个包含指定索引处值的字符串。

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

该函数只包含一个表达式或返回语句,可以使用箭头表示法缩短它:

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

作用域

Dart中的变量的作用域是由代码块决定的。可以根据{},来查看变量是否在作用域中。

下面是一个嵌套函数的例子,每个作用域级别都有变量:

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

闭包

闭包是一个函数对象,它可以访问其作用域内的变量,即使该函数在其作用域之外使用。

Function makeAdder(int addBy) {  return (int 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);}

函数返回值

所有函数都返回一个值。如果没有指定返回值,语句返回null。

foo() {}assert(foo() == null);int foo() {	return 1;}assert(foo() == 1);