如何在Kotlin中用函数式方式扁平化嵌套Role对象树获取全量角色列表
问题分析
原有代码存在以下核心问题:
- 边界判断逻辑错误:
rootRoles == null && roles == null && roles?.isEmpty() == true是永假表达式,roles为null时不可能同时满足isEmpty() == true - 递归逻辑混乱:递归过程中重复拼接根角色列表,会产生大量重复数据
- 空安全处理冗余:
Person类的roles是Set类型非空,不需要额外传递空值 - 缺少去重逻辑:嵌套层级中可能出现重复角色,未做去重处理会导致结果冗余
正确实现
方案1:扩展函数+递归实现(最简洁函数式风格)
给Role类扩展递归拉平方法,直接处理角色集合即可:
// 扩展方法:获取当前角色 + 所有嵌套子角色的平替列表 fun Role.flattenWithChildren(): List<Role> { val children = childrenRoles ?: emptyList() return listOf(this) + children.flatMap { it.flattenWithChildren() } } fun Person.resolveAllRoles(): List<Role> { return roles .flatMap { it.flattenWithChildren() } .distinctBy { it.id } // 按角色ID去重,避免不同路径返回相同角色 }
方案2:纯函数实现(无需扩展函数)
如果不想定义扩展函数,也可以用纯工具函数实现:
fun flattenAllRoles(roles: Collection<Role>): List<Role> { return roles.flatMap { role -> listOf(role) + (role.childrenRoles?.let { flattenAllRoles(it) } ?: emptyList()) }.distinctBy { it.id } } fun resolve(rootPerson: Person): List<Role> { return flattenAllRoles(rootPerson.roles) }
如果需要兼容入参为null的场景,可以调整函数签名:
fun flattenAllRoles(roles: Collection<Role>?): List<Role>? { return roles?.let { it.flatMap { role -> listOf(role) + (role.childrenRoles?.let { c -> flattenAllRoles(c) } ?: emptyList()) }.distinctBy { it.id } } }
方案3:尾递归实现(针对深嵌套场景)
如果角色嵌套层级很深(超过100层),可以用尾递归实现避免栈溢出:
tailrec fun flattenAllRolesTailRec(remaining: List<Role>, result: MutableSet<Role> = mutableSetOf()): List<Role> { if (remaining.isEmpty()) return result.toList() val current = remaining.first() result.add(current) val nextRemaining = remaining.drop(1) + (current.childrenRoles ?: emptyList()) return flattenAllRolesTailRec(nextRemaining, result) } fun Person.resolveAllRoles(): List<Role> = flattenAllRolesTailRec(roles.toList())
内容的提问来源于stack exchange,提问作者SlandShow
相关产品推荐
相关产品推荐

