Elm自定义类型如何模式匹配其余变体并提取字段值
问题核心
下面针对两个需求直接给出Elm生态下的标准实现方案:
1. 提取所有Planet变体的Name字段,避免冗余case
你现在逐一枚举变体的写法语法上完全合法,之所以写起来冗余,是因为你把所有变体共有的Name字段重复定义在了每个变体的构造参数里。
最优方案是重构类型定义,把公共字段抽离到所有变体共享的外层,从根源上消除重复解构的必要:
type alias Name = String type alias OrbitDays = Float -- 只把不同变体有差异的部分放在自定义类型里 type PlanetVariant = Mercury OrbitDays | Venus OrbitDays | Earth | Mars OrbitDays | Jupiter OrbitDays | Saturn OrbitDays | Uranus OrbitDays | Neptune OrbitDays | Pluto OrbitDays -- 公共字段放在外层记录里 type alias Planet = { name : Name , variant : PlanetVariant }
重构后提取名称根本不需要写case匹配,直接用记录访问语法一行搞定:
toName : Planet -> Name toName = .name
对应的行星列表初始化逻辑也更清晰:
planets : List Planet planets = [ { name = "Mercury", variant = Mercury 88.0 } , { name = "Venus", variant = Venus 224.68 } , { name = "Earth", variant = Earth } , { name = "Mars", variant = Mars 686.98 } -- 其余行星 , { name = "Pluto", variant = Pluto (247.7 * 365.25) } ]
如果你因为某些原因不能修改原有类型(比如类型来自第三方库),那逐一枚举所有变体的toName函数只需要写一次,抽成通用工具函数之后全项目复用即可,不会产生重复代码。Elm本身不提供自动跨变体提取同名字段的语法,因为自定义类型每个变体的参数数量、类型、含义本来就可以完全独立,编译器不会默认不同变体存在同构字段。
2. 匹配除特定变体外的其余所有变体
Elm的case语法 没有专门的“排除指定变体,匹配剩余所有”的语法糖,通配符_可以匹配所有未显式列出的变体,但不会自动解构变体内部的字段。
实际开发中按下面的方式写就能满足需求,代码非常简洁:
- 如果统一逻辑不需要用到变体内的字段:先写你需要特殊处理的变体分支,剩余分支直接用
_通配即可。比如要单独标记冥王星为矮行星,其余行星正常返回名称:planetLabel : Planet -> String planetLabel planet = case planet of Pluto _ _ -> toName planet ++ "(矮行星)" _ -> toName planet - 如果统一逻辑需要用到公共字段:提前写好类似
toName的公共字段提取函数,不管是特殊分支还是通用分支都直接调用即可,不需要在每个分支里重复解构。
不要觉得写一次全量case匹配是多余的:Elm的穷尽检查机制会在你后续新增/修改Planet变体的时候,直接在所有写了全量匹配的位置报编译错误,提醒你补全逻辑,从根源上避免漏改导致的bug,这本身就是类型系统的优势。
内容的提问来源于stack exchange,提问作者Carl
相关产品推荐
相关产品推荐

