Dart is a true object-oriented language, even its functions are objects and have their type Function. This also means that functions can be assigned to variables or passed as arguments to other functions. You can also call an instance of the Dart class as a method

Simple implementation of a function example

main(List<String> args) {
  List<int> myList = List<int> (3);
  // Since the length is fixed, no value can be added
  myList[0] =1;
  // myList.add(1);
  // myList.add(2);
  // myList.add(3);
  // List myList = [1, 2, 3];

  bool isNumber(int index) {
    returnmyList[index] ! =null;
  }
 
  print(myList.length);
  print(myList[0]);
  print(isNumber(0));

}
Copy the code

Although Effective Dart recommends using type annotations for public apis, this function still works if you omit types:

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

Arrow function

For functions that contain only one expression, you can use the shorthand syntax:

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

=>expression syntax is {return expression; }. The => symbol is sometimes called the fat arrow syntax ⚠️ note: in the arrow (=>) and semicolon (;) Only one expression (not a statement) can appear between. For example, you can’t put an if statement there, but you can use a conditional expression (ternary expression)

parameter

Functions can have two types of arguments: required and optional

  • The required parameters are defined in front of the parameter list
  • Optional parameters are definedAfter the required parameters
    • Optional arguments can be named or positional, but not both
    • The naming optional parameter can also be marked as **@required**

Optional named parameter

When calling a function, you can specify named parameters using paramName: value. Such as:

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

When defining functions, use {type param [,type2 param2]} to specify named parameters:

/// Set the [bold] and [Hidden] flags... Sets the [bold] and [hidden] flags...
main(List<String> args) {
  void enableFlags(name, {bool bold, bool hidden}) { print(name); }
  enableFlags("Zhang", bold: true);
}
Copy the code

Flutter instance creation expressions can be complicated, so the widget constructor uses only named parameters. This makes instance creation expressions easier to read

Comment a named parameter in any Dart code (not just Flutter) and use @required to indicate that it is a required parameter. Such as:

import 'package:meta/meta.dart';

class Scrollbar {
  Scrollbar({Key key, @required Widget child}) {}
}

void main(List<String> args) {}
Copy the code

If the caller attempts to construct a Scrollbar object through the constructor of the Scrollbar without providing the child argument, the compiler error @required is defined in the meta package, Dart can be used directly by importing package:meta/meta

Positional arguments

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

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


main(List<String> args) {
  // Here is an example of calling the above function without optional arguments:
  assert(say('Bob'.'Howdy') = ='Bob says Howdy');
	
  // 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

⚠️** Note: ** cannot use both an optional positional parameter and an optional named parameter

Default Parameter Value

Defaults can be defined for function named or positional arguments using =. The defaults must be compile-time constants and null if no default is specified. Here is an example of setting optional parameter defaults:

/// Set the [bold] and [Hidden] flags...
void enableFlags({bool bold = false.bool hidden = false{...}) } enableFlags(bold:true); // Bold will be true; And hidden is going to be false.
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:. This support is now obsolete, so we recommend that you use = to specify the default for now

The next example will show you how to set defaults for positional parameters:

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

main(List<String> args) {
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({
    Key key,
    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 an entry point to the program

  • The main() function returns void and can be omitted
  • And there is an optional argument of type List

Here is an example of the main() function for a Web application:

void main(List<String> args) {
    querySelector('#sample_text_id')
    ..text = 'Click me! '
    ..onClick.listen(reverseText);
}
Copy the code

Note: In the above code.. The syntax is called cascading invocation. Multiple operations can be performed on a single object using cascading access

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

Dart 1 2 3 test Run the application using the preceding command
void main(List<String> arguments) {
  print(arguments);
  assert(arguments.length == 4);
  assert(int.parse(arguments[0= =])1);
  assert(arguments[4] = ='test');
}
Copy the code

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

Function as a first-class object

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 an argument.
list.forEach(printElement);
Copy the code

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

main(List<String> args) {
  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 method with no name, called an anonymous function, or a Lambda expression or Closure Closure. You can assign an anonymous method to a variable and then use it, such as adding the variable to or deleting it from a collection

Anonymous methods look similar to named methods. Here’s the syntax

  • Parameters can be defined between parentheses, separated by commas
  • The following contents in braces are the body of the function:
([[type] parameter [,...]]) {function body; };Copy the code

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:

void main() {
  List<String> list = ['apples', 'bananas', 'oranges'];
  list.forEach((item) => print('${list.indexOf(item)}: $item'));
}
Copy the code

If there is only one line in the function body, you can use the fat arrow abbreviation

void main() {
  List<String> list = ['apples', 'bananas', 'oranges'];
  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. Variables defined in braces can only be accessed within braces, similar to Java and TS let const

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: 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 argument. Returns a function that adds [addBy] to the
// Function makeAdder(num addBy) {
// return (num i) => addBy + i;
// }

Function makeAdder(num addBy) =>  (num i) => addBy + i;

void main() {
  // Generate the function plus 2.
  var add2 = makeAdder(2);
  print(add2(3) = =5);

  // Generate a function that adds 4.
  var add4 = makeAdder(4);
  print(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() {} // define A top-level function

class A {
  static void bar() {} // Define static methods
  void baz() {} // Define instance methods
}

void main() {
  var x;

  // Compare whether the top-level functions are equal.
  x = foo;
  assert(foo == x);

  // Compare static methods for equality.
  x = A.bar;
  assert(A.bar == x);

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

  // These two closures refer to the same instance object, so they are equal.
  assert(y.baz == x);

  // These two closures refer to different instance objects, so they are not equal.
  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

Compared with python

class Kim(object) :
	def __init__(self, age =10 , *args, **kwargs) :
			self.age = age
			self.args = args
			self.kwargs = kwargs

	@staticmethod
	def methods(name = "Zhang") :
			return name


def main() :
	kim = Kim(1.2.3.4.5.6, a='7', c='b')
	print(kim.args, kim.kwargs) #(2, 3, 4, 5, 6) {'a': '7', 'c': 'b'}
	print(kim.methods())



if __name__ == '__main__':
	main()
Copy the code