dart_common_extensions:一套 Dart 常用扩展方法集合
前言
写 Dart / Flutter 时,你一定遇到过这些场景:
字符串转 int 要写
int.parse(s),还担心抛异常;日期格式化到处写DateFormat;列表想要个chunked还得自己写循环;Map 想取个不存在的 key 要加一大堆containsKey判断……
这些小操作本身不难,但每天写十几次,代码就变得啰嗦且容易出错。
这就是我开源dart_common_extensions的原因。
项目地址:github.com/ceeyang/dart_common_extensions
Pub 地址:pub.dev/packages/dart_common_extensions
⭐150+ 扩展方法,覆盖 String / DateTime / List / Map / Num / Enum / Object 📦 零运行时依赖(仅 decimal + intl) 🧪100+ 单元测试 📄 完整 API 文档 + 示例代码安装
dependencies: dart_common_extensions: ^0.0.9# Flutter 项目flutter pub get# 纯 Dart 项目dart pub get核心功能一览
📎 Object Extensions — 函数式编程小工具
Kotlin 开发者会非常熟悉let和also,Dart 里也能用了:
// let:对非空对象执行操作并返回结果 final length=userInput?.let((it)=>it.length)??0;//also:对对象执行副作用并返回对象本身 someObject.also((it)=>print('Processing:$it'));// 空安全判断 print(someObject.isNull);//true/falseprint(someObject.isNotNull);//true/false🧵 String Extensions — 字符串处理的瑞士军刀
这是这个包里最常用的部分。类型转换、校验、格式化、大小写变换,一行搞定:
类型转换:
'12'.toInt;//12'12.34'.toDouble;//12.34'2023-01-01'.toDate;// DateTime(2023,1,1)'{"key":"value"}'.toJson;//{key: value}'1,2,3'.toIntList;//[1,2,3]校验方法:
'13912345678'.isChineseMobile;//true'user@example.com'.isEmail;//true'192.168.1.1'.isIP;//true'{"a":1}'.isJson;//true'SGVsbG8='.isBase64;//true'https://example.com'.isValidUrl;// true(支持 localhost、IP、自定义端口)'AFFE'.isValidHex;//true大小写转换:
'hello_world'.toCamelCase;// helloWorld'helloWorld'.toSnakeCase;// hello_world'hello-world'.toKebabCase;// hello-world'hello world'.toTitleCase;// Hello World字符串操作:
'This is a long text'.truncate(10);//'This is a ...''user@example.com'.substringBefore('@');//'user''hello'.capitalize;//'Hello''Hello World'.removeAllSpaces;//'HelloWorld'📅 DateTime Extensions — 日期时间不头疼
格式化:
final now=DateTime.now();now.ymd;//"2026-07-15"now.dmy;//"15-07-2026"now.iso8601;//"2026-07-15T12:00:00"now.fullDateTime;//"2026-07-15 12:00:00"now.monthYear;//"July 2026"now.shortDate;//"7/15/2026"(locale dependent) now.longDate;//"July 15, 2026"(locale dependent) now.time;//"12:00:00"字符串也可以直接格式化:
'2023-01-01'.ymd;//"2023-01-01"'2023-01-01'.fullDateTime;//"2023-01-01 00:00:00"'1672531200000'.ymd;//"2023-01-01"(时间戳也支持)日期计算:
now.startOfDay;// 当天 00:00:00.000 now.endOfDay;// 当天23:59:59.999 now.isToday;//true/falsenow.nextDay;// 明天 now.isLeapYear;// 是否闰年 now.daysInMonth;// 当月天数 // 工作日计算 DateTime friday=DateTime(2023,1,6);friday.addBusinessDays(1);// 下周一(跳过周末) friday.subtractBusinessDays(1);// 上周四 DateTime(2023,1,7).isWeekend;// true(周六)📋 List & Iterable Extensions — 集合操作大补全
安全访问:
['a','b','c'].safeElementAt(5);// null(不抛异常)[1,2,3,4,5].firstWhereOrNull((e)=>e>10);// null分组与变换:
[1,2,3,4,5].chunked(2);//[[1,2],[3,4],[5]][1,2,3,4].windowed(2);//[[1,2],[2,3],[3,4]][1,2].zip(['a','b']);//[[1,'a'],[2,'b']][1,2,3].mapIndexed((i, e)=>'$i: $e');//['0: 1','1: 2','2: 3']统计聚合:
[1,2,3,4].sum;//10[1,2,3,4].average;//2.5[1,2,3,4].max;//4[1,2,3,4].min;//1[1,2,3,4].count((i)=>i>2);//2实用方法:
[1,2,3].random;// 随机元素[1,2,3].shuffled;// 打乱后的新列表[1,2,3].groupBy((e)=>e.isEven ?'even':'odd');//{'odd':[1,3],'even':[2]}[null, null].isAllNull;//true🗺️ Map Extensions — 安全又灵活
var map={'first':1,'second':2};map.getOrDefault('third',0);//0(不抛异常) map.getOrNull('third');// null map.toJsonString();//'{"first": 1, "second": 2}'// 过滤 map.pick(['first']);//{'first':1}map.omit(['first']);//{'second':2}map.filterKeys((k)=>k.startsWith('f'));//{'first':1}map.filterValues((v)=>v>1);//{'second':2}//合并 {'a':1}.merge({'a':2,'b':3});//{'a':2,'b':3} {'a':1}.merge({'a':2},(v1,v2)=>v1+v2);//{'a':3}//变换 {'a':1}.mapKeys((k,v)=>k.toUpperCase());//{'A':1}{'a':1}.mapValues((k,v)=>v+1);//{'a':2}🔢 Num Extensions — 数字也可以有语法糖
时间 Duration:
5.seconds;// Duration(seconds:5)1.5.days;// Duration(hours:36)60.secondsDuration;//0:01:00.000000 await5.secondsDelay();// 延迟5秒格式化:
1024.toFileSize();//"1.00 KB"123456.78.toCurrency(symbol:'€');//"€123,456.78"1234.567.toMoney(decimalDigits:1);//"1,234.6"255.toHexString;//"ff"10.toBinaryString;//"1010"0.1234.toPercentage();//"12.34%"数学:
1.rangeTo(5);//[1,2,3,4,5]5.rangeTo(1);//[5,4,3,2,1]1.sumTo(5);//152.power(3);//85.isPrime;//true2.isEven;//true🔁 Enum Extensions — 循环导航
enum Status{active, inactive}Status.active.next(Status.values);// Status.inactive Status.inactive.previous(Status.values);// Status.active特别适合分页状态机、步骤导航等场景。
为什么自己造这个轮子?
Dart 生态中其实不缺扩展库,比如dartx、basics、supercharged等。选择自建一个,有几个原因:
- 按需定制:只收录日常真的会用到的扩展,不做大而全的"百宝箱"
- 中文友好:内置了
isChinese、isChineseMobile等中文场景校验 - 简单透明:代码量不大,每个扩展方法都清晰可查,遇到问题直接看源码比翻文档快
- 零学习成本:所有方法命名都是自解释的,看一眼就知道干嘛用的
项目状态与路线图
当前版本0.0.9,2026年5月底初次发布,已有 150+ 扩展方法和 100+ 单元测试。
后续计划:
Num扩展:货币格式化、范围生成、延迟List扩展:windowed、zip、groupByString扩展:百分比、Base64、URL 编码- Iterable扩展补充:更多懒加载操作
- Duration扩展:人类可读格式
- Null扩展:
isNull/isNotNull顶层函数 - 更多本地化日期格式
欢迎提 Issue 或 PR 贡献你常用的扩展方法。
结语
dart_common_extensions不是什么惊天动地的项目,它是一个工具箱——把每天写 Dart / Flutter 时那些"又来一遍"的操作封装起来,让代码更短、更清晰、更安全。
项目是完全开源的(MIT 协议),欢迎 Star、Issue 和 PR:
👉 github.com/ceeyang/dart_common_extensions
如果你也在写 Dart / Flutter,不妨试一试,加一行依赖就能省下不少样板代码。