在Dart语言中,函数也是对象,这点和其他语言有点不一样。
函数是一等对象
Dart 是完全面向对象语言,函数本身也是对象,类型为 Function。
可赋值给变量、作为参数传给其他函数;
类实例可直接像函数一样调用
1 标准函数定义
// 完整带返回值、参数类型标注
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
Code language: Dart (dart)
完整例子
// 稀有气体原子号映射表
final Map<int, String> _nobleGases = {
2: 'He',
10: 'Ne',
18: 'Ar',
36: 'Kr',
54: 'Xe',
86: 'Rn',
};
// 完整带返回值、参数类型标注
// int 不可空,不能传入 null,所以改为 int? 支持空参数
bool isNoble(int? atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void main() {
print(isNoble(null)); // null不在map键中 → false
print(isNoble(2)); // 存在稀有气体 → true
print(isNoble(9)); // 不存在 → false
print(isNoble(86)); // 存在 → true
}
Code language: Dart (dart)
false
true
false
trueCode language: JavaScript (javascript)
2 省略类型
Effective Dart 编码规范建议,对外暴露的公共接口(公开 API)必须手动标注完整类型。
如果你是内部的函数,则可以省略类型
例如
final Map<int, String> _nobleGases = {
2: 'He',
10: 'Ne',
18: 'Ar',
36: 'Kr',
54: 'Xe',
86: 'Rn',
};
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void main() {
print(isNoble(null)); // null不在map键中 → false
print(isNoble(2)); // 存在稀有气体 → true
print(isNoble(9)); // 不存在 → false
print(isNoble(86)); // 存在 → true
}
Code language: Dart (dart)
上面例子,isNoble函数,去掉了返回类似bool,参数也省略了int?类型。仍然可以正常使用。
当你不写类型时,Dart 会自动推断类型:
- 参数
atomicNumber:无显式类型 → 推导类型为dynamic(动态类型,任意值都能传:数字、字符串、null 都行) - 返回值:无前置类型标注 → Dart 根据
return右边表达式推断出返回bool,只是代码不写出来
为什么公开 API 一定要写类型?
可读性:别人调用你的函数,一眼看懂入参、返回值是什么类型,不用读内部代码猜;
类型安全:dynamic 动态类型关闭静态检查,传错类型不会编译报错,容易线上崩溃;
IDE 提示:标注类型后编辑器会自动补全、参数提示;无类型时 IDE 无法精准提示。
什么时候可以省略类型?
仅建议局部私有代码,函数只在当前文件内部使用、不对外被调用。
箭头简写语法(=>)
当你的函数里面的函数体({}中的代码),只有一句返回表达式的时候,可以使用简写成箭头函数。
例如
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
Code language: Dart (dart)
=> expr等价于{ return expr; };- 箭头与分号之间只能写表达式,不能写语句(如
if,可用三元表达式替代)。
// 稀有气体原子序数映射表
final Map<int, String> _nobleGases = {
2: '氦',
10: '氖',
18: '氩',
36: '氪',
54: '氙',
86: '氡',
};
// 箭头简写函数:单行表达式直接返回,等价于带 return 的块函数
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
void main() {
// 测试存在的稀有气体
print(isNoble(2)); // true
print(isNoble(18)); // true
// 测试普通元素
print(isNoble(6)); // false(碳)
print(isNoble(99)); // false(无对应元素)
}
Code language: Dart (dart)

Parameters 参数
函数支持必选位置参数,其后只能二选一:命名参数 / 可选位置参数,不能混用。
调用 / 定义参数时支持尾随逗号 ,,提升代码可读性。
1. 命名参数 Named parameters
用 {} 包裹,默认可选;加 required 强制传参。
1)基础可空命名参数(无默认值,默认是null,类型必须可空 ?)
void enableFlags({bool? bold, bool? hidden}) {}
// 调用时显式指定参数名
enableFlags(bold: true, hidden: false);
Code language: Dart (dart)
完成例子
/// 开启文本样式标记:加粗、隐藏
void enableFlags({bool? bold, bool? hidden}) {
print('加粗:$bold,隐藏:$hidden');
}
void main() {
// 完整传所有命名参数
enableFlags(bold: true, hidden: false);
// 只传其中一个命名参数,另一个为 null
enableFlags(bold: true);
// 只传 hidden
enableFlags(hidden: true);
// 不传任何参数,两个值都是 null
enableFlags();
}
Code language: Dart (dart)
执行结果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
加粗:true,隐藏:false
加粗:true,隐藏:null
加粗:null,隐藏:true
加粗:null,隐藏:nullCode language: JavaScript (javascript)
2)设置编译期常量默认值(无需可空),因为已经又默认值了,所以不为可空也可以
void enableFlags({bool bold = false, bool hidden = false}) {}
enableFlags(bold: true); // hidden 自动取 false
Code language: Dart (dart)
例子
/// 开启文本样式标记:加粗、隐藏
void enableFlags({bool bold = false, bool hidden = false}) {
print('加粗:$bold,隐藏:$hidden');
}
void main() {
enableFlags();//不传参数两个参数有默认值 上面设置都是false 加粗:false,隐藏:false
}
Code language: Dart (dart)
3)强制必传命名参数 required(注:Flutter 组件构造器经常用到) 如下例子是Flutter,读者可以到Flutter的课程中学习。
const Scrollbar({super.key, required Widget child});
// required 参数也允许可空类型
const Scrollbar({super.key, required Widget? child});
Code language: Dart (dart)
Dart 不强制命名参数必须放末尾,可穿插在参数列表任意位置
repeat(times: 2, () {})Code language: CSS (css)
2. 可选位置参数 Optional positional parameters
用 [] 包裹,不传时默认 null,可设置常量默认值。
// 无默认值,类型带 ?
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');
Code language: Dart (dart)
完整例子
// [String? device] 可选位置参数,无默认值,不传则为 null
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device'; //如果device不为null,则再信息的后面带上设备
}
return result;
}
void main() {
// 不传第三个可选参数
String res1 = say('Bob', 'Howdy');
print(res1);
// 传入第三个可选位置参数
String res2 = say('Bob', 'Howdy', 'smoke signal');
print(res2);
// 手动传 null 给可选参数
String res3 = say('Alice', 'Hi', null);
print(res3);
}
Code language: Dart (dart)
设置默认值:
String say(String from, String msg, [String device = 'carrier pigeon']) {
return '$from says $msg with a $device';
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');
Code language: Dart (dart)
完整例子
// 可选位置参数,设置默认值 carrier pigeon(信鸽)
String say(String from, String msg, [String device = 'carrier pigeon']) {
return '$from says $msg with a $device';
}
void main() {
// 不传第三个可选参数,自动使用默认值 carrier pigeon
String res1 = say('Bob', 'Howdy');
print(res1); //Bob says Howdy with a carrier pigeon
// 手动传入自定义设备,覆盖默认值
String res2 = say('Bob', 'Howdy', 'smoke signal');
print(res2); //Bob says Howdy with a smoke signal
String res3 = say('Alice', 'Hello', 'mobile phone');
print(res3); // Alice says Hello with a mobile phone
String res4 = say('Jack', 'Tom', 'website foxdevelop.com');
print(res4); // Jack says Tom with a page
}
Code language: Dart (dart)
执行结果
Built firstdart:firstdart.
Bob says Howdy with a carrier pigeon
Bob says Howdy with a smoke signal
Alice says Hello with a mobile phone
Jack says Tom with a website foxdevelop.comCode language: JavaScript (javascript)
main () 入口函数
所有 Dart 程序必须存在顶层 main(),是程序唯一入口。
- 无参基础版本
void main() {
print('Hello, wellcome to foxdevelop.com!');
}
Code language: Dart (dart)
Hello, wellcome to foxdevelop.com!Code language: CSS (css)
- 命令行程序接收启动参数
// 执行命令:dart run firstdart.dart 1 test
void main(List<String> arguments) {
print(arguments); // [1, test]
}
Code language: Dart (dart)
复杂命令行参数解析可使用官方 args 库。
上面的firstdart.dart 要改为你的dart文件名

函数作为一类对象 First-class objects
1. 函数作参数传递
void printElement(int element) => print(element);
var list = [1, 2, 3];
list.forEach(printElement); // 直接传入函数
Code language: Dart (dart)
完整例子
void main() {
void printElement(int element) => print(element);
var list = [1, 2, 3];
list.forEach(printElement); // 直接传入函数
}
Code language: Dart (dart)
输出
1
2
3
2. 匿名函数赋值给变量
void main() {
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
print(loudify('hello')); //!!! HELLO !!!
}
Code language: Dart (dart)
函数类型 Function Type
可显式声明函数变量类型
格式:返回值 Function(形参列表, {命名参数})
void greet(String name, {String greeting = 'Hello'}) => print('$greeting $name!');
// 定义函数类型变量
void Function(String, {String greeting}) g = greet;
g('Dash', greeting: 'Howdy');
Code language: Dart (dart)
可通过 typedef 给函数类型起别名,复用、提升可读性。
{String greeting}) → 带一个命名参数 greeting,类型 String
void main() {
void greet(String name, {String greeting = 'Hello'}) => print('$greeting $name!');
// 定义函数类型变量
void Function(String, {String greeting}) g = greet;
g('Jack', greeting: 'Howdy');
}
Code language: Dart (dart)
输出
Howdy Jack!
匿名函数(Lambda / Closure 闭包)
无函数名的函数,两种写法:
- 代码块写法(多行)
void main() {
const list = ['apples', 'bananas'];
var uppercaseList = list.map((item) {
return item.toUpperCase();
}).toList();
print(uppercaseList);
}
Code language: Dart (dart)
上面代码中的 (item) { return item.toUpperCase(); } 就是匿名函数(lambda)
输出:[APPLES, BANANAS]
- 箭头简写(单行表达式)
void main() {
const list = ['fox', 'develop','foxdevelop.com'];
var uppercaseList = list.map((item) => item.toUpperCase()).toList();
uppercaseList.forEach((item) => print('$item: ${item.length}'));
}
Code language: Dart (dart)
输出
FOX: 3
DEVELOP: 7
FOXDEVELOP.COM: 14Code language: HTTP (http)
词法作用域 Lexical scope
Dart 采用静态词法作用域:变量作用域由代码大括号层级决定,内层可访问外层所有变量。
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
// 全部可访问
assert(topLevel && insideMain && insideFunction && insideNestedFunction);
}
}
}
Code language: Dart (dart)
词法闭包 Lexical closures
闭包:函数对象可以捕获并持有外层作用域变量,脱离原作用域后仍能访问。
Function makeAdder(int addBy) {
// 捕获外部变量 addBy
return (int i) => addBy + i;
}
void main() {
var add2 = makeAdder(2);
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
Code language: Dart (dart)
下面对上面的执行过程进行逐步分析
第一步:var add2 = makeAdder(2);
- 执行
makeAdder,传入addBy = 2 - 创建匿名函数:
(int i) => 2 + i - 将这个函数赋值给变量
add2,也就是这个时候add2其实是一个函数对象 它的函数体是(int i) => 2 + i传入int i 返回i+2 makeAdder函数执行结束,但匿名函数牢牢记住addBy=2
第二步:var add4 = makeAdder(4);
- 再次执行
makeAdder,传入addBy = 4 - 创建全新独立的匿名函数:
(int i) => 4 + i - 赋值给
add4,它单独保存一份addBy=4,和 add2 互不干扰,也就是addBy在两个函数对象add2和add4中,被记录到了函数体里面,一个里面的addBy是2 一个的addBy是4
makeAdder(2)执行时,会生成一个独立闭包,单独绑定一份addBy = 2,赋值给add2;makeAdder(4)执行时,生成另一个全新闭包,单独绑定一份addBy = 4,赋值给add4;add2和add4是两个完全互不干扰的函数对象,各自私有存储捕获的addBy,互不影响。
第三步:调用 add2(3)
执行内部函数:2 + 3 = 5,断言成立
第四步:调用 add4(3)
执行内部函数:4 + 3 = 7,断言成立
函数截取 Tear-offs
调用函数 / 方法时不加括号,会生成 tear-off(轻量闭包),替代手写匿名 lambda,代码更简洁。
推荐写法,直接传入函数就可以。
var charCodes = [68, 97, 114, 116];
var buffer = StringBuffer();
charCodes.forEach(print); // 函数截取
charCodes.forEach(buffer.write); // 方法截取
Code language: Dart (dart)
冗余写法
charCodes.forEach((code) => print(code));
charCodes.forEach((code) => buffer.write(code));
Code language: Dart (dart)
函数相等性判断
- 顶层函数、静态方法:函数名完全相等则
==; - 实例方法:只有绑定同一个对象实例的方法截取才相等。
void foo() {}
class A {
static void bar() {}
void baz() {}
}
void main() {
var x = foo;
assert(foo == x);
x = A.bar;
assert(A.bar == x);
var v = A(), w = A(), y = w;
x = w.baz;
assert(y.baz == x); // 同一实例,相等
assert(v.baz != w.baz); // 不同实例,不相等
}
Code language: Dart (dart)
返回值 Return values
- 所有函数必有返回值:无显式
return时,隐式追加return null;
foo() {}
assert(foo() == null);
Code language: Dart (dart)
- 返回多个值:使用 Record 记录元组
(String, int) foo() {
return ('something', 42);
}
Code language: Dart (dart)
Getter & Setter 存取器
所有属性读取 / 赋值本质是调用 getter /setter;普通变量自动生成隐式存取器,也可手动显式定义。
优势:对外统一 .属性 调用,内部逻辑可随时修改,无需改动外部代码。
String _secret = 'Hello';
// Getter 读取
String get secret {
print('调用getter');
return _secret.toUpperCase();
}
// Setter 赋值
set secret(String newMsg) {
print('调用setter');
if (newMsg.isNotEmpty) _secret = newMsg;
}
void main() {
print(secret); // 读取,触发getter → HELLO
secret = 'Dart is fun'; // 赋值,触发setter
print(secret); // DART IS FUN
}
Code language: Dart (dart)
* 生成器 Generators
惰性按需生成序列,分同步、异步两种,使用 yield 产出值。
- 同步生成器
sync*,返回Iterable
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
Code language: Dart (dart)
- 异步生成器
async*,返回Stream
Stream<int> asyncNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
Code language: Dart (dart)
- 递归生成器优化
yield*(转发另一个生成器,提升性能)
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
Code language: Dart (dart)