function

Dart is a true object-oriented language, so even functions are objects and of type Function, which means functions can be assigned to variables or as arguments to other functions. You can also call an instance of the Dart class as if it were a function. See callable classes for details.

An example of a simple function implementation:

main() {
  var list = [];
  list.addAll([1.2.null]);

  bool isNumber(int index) {
    returnlist[index] ! =null;
  }

  print(list);
  print(isNumber(0)); // true
}
Copy the code

Although the Efficient Dart guide recommends defining return types on public apis, this function is still valid even if it is not:

isNumber(int index) { returnlist[index] ! =null; }
Copy the code

If the function body contains only one expression, you can use shorthand syntax:

bool isNumber(intindex) => list[index] ! =null;
Copy the code

Syntax => Expressions are {return expressions; }, => is sometimes called the arrow function.

In = > and; Can only be expressions, not statements. For example, you can’t put an if statement in it, but you can put conditional expressions.

parameter

Functions can take two forms of arguments: required and optional. The required parameters are defined before the parameter list, and the optional parameters are defined after the required parameters. Optional arguments can be named or positional.

Some apis (especially the constructor of the Flutter control) only use named parameters, even if they are mandatory. See the next section for more information.

You can use [trailing comma] when passing parameters to or defining function parameters.

Named parameters

Named parameters default to optional, unless they are specifically marked as required.

When you call a function, you can specify named arguments in the form of parameter names: parameter values. Such as:

enableFlags(bold: true, hidden: false);
Copy the code

When defining a function, use {arguments 1, 2… } to specify named arguments:

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

If the argument is optional but cannot be null, a default value is provided. Although named parameters are one type of optional parameter, you can still use required to indicate that a named parameter is required, in which case the caller must provide a value for the parameter. Such as:

const Scrollbar({Key? key, required Widget child})
Copy the code

If the caller wants to construct a Scrollbar object through the constructor of the Scrollbar without providing the child argument, it causes a compilation error.

Optional position parameter

Use [] to wrap a series of arguments as positional arguments:

String say(String from, String msg, [String? device]) {
  var result = '$from says $msg';
  if(device ! =null) {
    result = '$result with a $device';
  }
  return result;
}
Copy the code

Here is an example of calling the above function without optional arguments

assert(say('Bob'.'Howdy') = ='Bob says Howdy');
Copy the code

Here is an example of calling the above function with optional arguments:

assert(say('Bob'.'Howdy'.'smoke signal') = ='Bob says Howdy with a smoke signal');
Copy the code

Default Parameter Value

You can use = to define default values for the function’s named and positional arguments. The default value must be a compile-time constant, or null if no default is specified.

The following is an example of setting optional parameter defaults:

/// 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);
Copy the code

Older versions of Dart code used the colon (:) instead of = to set the default values for named parameters. The reason is that at first the named argument only supported:. However, this support is now obsolete, so we recommend that you specify the default value only with = for now.

Here is setting the default value for the position parameter:

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');
Copy the code

List or Map can also be used as defaults. The following example defines a function called doStuff() and specifies a list and Map value for its arguments named List and Gifts.

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

The main () function

Each Dart program must have a main() top-level function as its entry point, which returns void and takes an optional argument of type List

.

Here’s a simple main() function:

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

Here is an example of using the command line to access the main() function with arguments:

// 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');
}
Copy the code

You can define and parse command-line arguments by using argument libraries.

Functions are first-class objects

You can pass a function as an argument to another function. Such as:

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

var list = [1.2.3];

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

You can also assign a function to a variable, as in:

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

Anonymous functions

Most methods have names, such as main() or printElement(). You can create a nameless method called an anonymous function, a Lambda expression, or a Closure Closure. You can assign an anonymous method to a variable and then use it, such as adding the variable to or removing it from a collection.

Anonymous methods look similar to named methods in that arguments can be defined between parentheses, separated by commas.

The following contents in braces are the body of the function:

([[type] parameter [,...]]) {function body; };

The following code defines an anonymous method that takes only one parameter item and has no parameter type. This function is called for each element in the List, printing a string of element positions and values:

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

If the function has only one return line, you can use the fat arrow abbreviation. Paste the following code into DartPad and click the Run button to verify that the two functions are the same.

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

Lexical scope

Dart is a lexical scoped language. Variables are scoped at code writing time, and variables defined in braces can only be accessed within braces, similar to Java.

Here is an example of a nested function with variables in multiple scopes:

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); }}}Copy the code

Note that the nestedFunction() function can access all variables, including the top-level variable.

Lexical closures

A closure is a function object that can access variables in its lexical scope even if the function object is called outside its original scope.

A function can enclose variables defined in its scope. In the following example, the function makeAdder() captures the variable addBy. Whenever the function returns, it can use the captured addBy variable.

/// Returns a function that adds [addBy] to the
/// function's argument.
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);
}
Copy the code

Tests whether the functions are equal

Here is an example test of equality between top-level functions, static methods and sample methods:

void foo() {} // A top-level function class A { static void bar() {} // A static method void baz() {} // An instance method } void main() { Function 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); }Copy the code

The return value

All functions return values. The last line of a function that does not display a return statement defaults to return NULL; .

foo() {}

assert(foo() == null);
Copy the code