▲Dart-函数

Dart,一切都是一个对象,包括函数,这意味着您可以将函数存储在变量中,并以与传递String、int或任何其他对象相同的方式在应用程序中传递函数。这被称为具有一级函数(first-class functions),因为它们被视为等同于其他类型,而不是语言中的二级公民(second-class citizens)。

1. void go(...){
    
    ...snip...;}
2. go(...){
    
    ...snip...;}

第1行代码,明确表示没有返回值。
第2行代码,没有return语句,它等效于return null; 即,有返回值null。
第2行代码,相当于返回类型是dynamic

dynamic、var、Object 三种类型的区别:
dynamic:所有Dart对象的基础类型,在大多数情况下,不直接使用它。通过它定义的变量会关闭类型检查,这意味着 dynamic x= ‘hal’; x.foo();这段代码静态类型检查不会报错,但是运行时会crash,因为 x 并没有foo()方法,所以建议大家在编程时不要直接使用dynamic;
var: 是一个关键字,意思是"我不关心这里的类型是什么",系统会自动判断运行时类型(runtimeType);
Object: 是Dart对象的基类,当你定义:Object o =xxx ;时这时系统会认为 o 是个对象,你可以调用o的toString()和hashCode()方法,因为Object 提供了这些方法,但是如果你尝试调用o.foo()时,静态类型检查会运行报错。
综上不难看出dynamic与Object的最大的区别是在静态类型检查上。

以下两函数等效:

calculateQty(ingredient, numberOfCementBags, proportion) {
    
    
	// ...snip...
}
calculateQty(dynamic ingredient, dynamic numberOfCementBags, dynamic proportion) {
    
    
	// ...snip...
}

关于按引用与按值传递

Dart中Number,String,Bool等都是不可变的(immutable),每次修改都是产生一个新的对象。而其他大部分对象都是可变的(mutable)。

  var a = ['Apple', 'Orange'];
  var b = a; // a,b引用同一个内存对象,但a,b之间无任何联系!
  a = ['Banana']; // a进行赋值操作,对b没有影响,a现在引用一个新对象,b还是引用原内存对象
  print("result:a=$a,b=$b");// a=[Banana],b=[Apple, Orange]

  var m = ['Apple', 'Orange'];
  var n = m;
  m.clear();// 清空m引用的list,而n一直引用这个内存对象,即n中内容被清空
  m.add('Banana');// 由于此时m、n都引用同一list,所以变化对m和n是同步的
  print("result:m=$m,n=$n");// m=[Banana],n=[Banana]

  String str = "abc";
  tryChangeOriginStr(str);
  print("result:" + str);// abc

  var box = Box();
  tryChangeOriginClz(box);
  print("result:${box.x}");// 16
}

void tryChangeOriginStr(String str) {
    
    // 传值(by value),传递进来的参数自动拷贝一份,即用拷贝在函数体完成逻辑
  str += "XYZ";
}
void tryChangeOriginClz(Box box) {
    
    // 传引用(by reference),传递进来的参数是一个引用,即用传递来的对象在函数体完成逻辑
  box.x *= 2;
}

class Box {
    
    
  num x = 8;
}

可选参数列表

measureQty(ingredient, [int numberOfCementBags, int proportion]) {
    
    
	// ... snip ...(null判断)
}
// 可以像如下调用以上的函数
main() {
    
    
	measureQty(new Sand(), 2, 1);
	measureQty(new Sand(), 2);
	measureQty(new Sand());
}

还可以在命名参数的函数声明中提供默认值:

measureQty(ingredient, [int numberOfCementBags = 1, int proportion = 1]) {
    
    
	return ingredient * (numberOfCementBags * proportion);
}

可选命名参数:

measureQty(ingredient, {
     
     int numberOfCementBags:1, int proportion:1}) {
    
    
	return ingredient * (numberOfCementBags * proportion);
}
main() {
    
    
	measureQty(new Sand(), numberOfCementBags: 2, proportion: 1);
	measureQty(new Sand(), numberOfCementBags: 2);
	measureQty(new Sand(), proportion: 1);
	measureQty(new Sand());
}

Function类型:

var mortar = mix(sand, cement);
var mixFunction = mix;
var dryConcrete = mixFunction(mortar, gravel);
print(mix is Object);// true,函数是个Object对象
print(mix is Function);// true,函数是Function类型
print(dryConcrete is Object);// true,一切皆对象
print(dryConcrete is Function);// false,它只是函数对象的引用,而并非是函数类型
var mix4 = Ingredient mixer(Ingredient item1, Ingredient item2) {
    
    
	// do something
}

以上声明中,名称mixer()本质上是一次性的。它仅在函数范围内可用,在其他地方无效。除了它本身之外,不能在任何地方引用mixer()。

可以定义强函数类型:

// mixFunc参数是一个Function的强类型
Ingredient combineIngredients(Function mixFunc, item1, item2) {
    
    
	return mixFunc(item1, item2);
}

Function mix = (item1, item2) {
    
    
    return item1 + item2;
}

typedef关键字声明函数签名,从而创建自定义函数类型。
所谓函数签名,就是函数的参数类型和返回类型。

typedef Ingredient MixFunc(Ingredient, Ingredient);// 此时MixFunc是一个自定义的函数类型
Ingredient combineIngredients(MixFunc mixFunc, item1, item2) {
    
    // 使用MixFunc这个函数类型,传入的函数参数必须满足函数签名
	return mixFunc(item1, item2);
}
main() {
    
    
	var cement = new Cement();
	mix(item1, item2) {
    
    // 局部函数定义
		return cement + item1 + item2;// 当然,可以直接访问cement
	}
}

猜你喜欢

转载自blog.csdn.net/itzyjr/article/details/122389534