函数式编程:声明式编程与命令式编程的区别及疑问解析
关于函数式编程与命令式封装的核心差异
仅封装循环逻辑为公共库,完全不代表团队从命令式开发切换到了声明式/函数式开发,这种相似只是接口层面的表象,二者的核心差异体现在底层开发逻辑和约束上
- 首先要明确两种范式的核心定义差异
函数式属于声明式范式的子集,核心要求是「描述目标结果,而非描述实现路径」,这个要求不是靠封装接口就能实现的,是靠整个范式对代码逻辑的约束落地的。而命令式范式的核心是「按步骤描述程序要执行的操作」,哪怕你把循环包成了filter方法,只要逻辑还是围绕修改外部状态、依赖副作用实现,本质还是命令式。 - 函数式的核心约束远不止接口封装
真正的函数式开发需要满足几个核心规则,这是普通命令式团队封装公共库不会刻意遵守的:- 纯函数优先:所有工具方法默认是纯函数,输出仅由输入决定,不会修改输入参数、也不会修改任何外部状态,同样的输入永远返回相同的输出。比如Scala的
filter不会修改原集合,只会返回新的过滤后的集合,而很多命令式团队封装的公共工具,很可能会直接修改原入参,本质还是命令式的状态修改思路。 - 不可变性默认:函数式范式下默认使用不可变数据结构,任何修改都会生成新的实例,从根源上避免了状态变更带来的隐性问题,这是整个开发思路的转变,和封装工具完全无关。
- 表达式优先:函数式中的操作基本都是有返回值的表达式,而非没有返回值、仅靠副作用生效的语句,整个逻辑可以通过表达式的组合实现,不需要额外的中间状态变量。
- 纯函数优先:所有工具方法默认是纯函数,输出仅由输入决定,不会修改输入参数、也不会修改任何外部状态,同样的输入永远返回相同的输出。比如Scala的
- 举个直观的对比
同样是用封装好的filter方法过滤列表中大于10的元素:
包了壳的命令式写法:
你还是在手动管理结果集合的状态,描述了「把符合条件的元素塞到结果数组里」这个步骤,本质还是命令式。let result = [] myList.filter(item => { if (item > 10) result.push(item) })
真正的函数式写法:
你只需要描述「我要列表里大于10的元素」这个目标,完全不需要管循环怎么跑、结果怎么收集,也没有任何外部状态修改,这才是声明式的核心。val result = myList.filter(_ > 10)
内容的提问来源于stack exchange,提问作者Mandroid
相关产品推荐
相关产品推荐

