在泛型函数结合结构体的场景下,defclass的价值体现在何处?
在Common Lisp里,defclass能给泛型函数+结构体的组合补上几个结构体天生缺失的关键能力,让你的泛型编程体系更灵活、可扩展:
灵活的继承与方法复用
结构体的继承仅能通过:include实现简单的结构拷贝,没法做到行为上的继承复用。而类支持多继承和完整的方法调度链:你可以先定义一个基类api-account-key,在它上面实现build-url的通用逻辑(比如拼接Hunter API的基础域名、添加通用参数),再让lead-account-key和campaign-account-key这两个子类继承基类,各自只实现差异化的路径拼接逻辑。调用build-url时,会自动沿着继承链触发父类的通用逻辑,不用在每个方法里重复写相同代码。而结构体的话,你只能给每个结构体类型单独编写build-url方法,重复代码无法避免。强大的方法组合能力
泛型函数的方法组合特性(比如:before/:after/:around修饰符)只有在类体系下才能完全发挥作用。比如你想给所有API账号类型的build-url统一加参数合法性校验,只需要给基类api-account-key添加一个:before方法就行,所有子类的build-url调用都会自动先执行这个校验。结构体的方法不支持这种组合方式,你得在每个结构体的build-url方法里手动重复校验代码。动态类型适配
类实例可以通过change-class在运行时切换类型——比如把一个lead-account-key实例转换成campaign-account-key,之后调用build-url会自动匹配新类型的方法。结构体的类型是静态的,一旦创建就无法修改,完全做不到这种动态适配场景。元编程与扩展性
类拥有完整的元对象协议(MOP)支持,你可以在运行时动态查询类的结构、添加/修改方法,甚至根据类的槽定义自动生成build-url的逻辑。比如你可以写一个工具函数,给所有带api-path-suffix槽的类自动生成对应的build-url方法。结构体的元信息非常有限,没法实现这种灵活的元编程扩展。封装与访问控制
类可以通过槽的:reader/:writer/:accessor参数控制内部数据的访问权限,比如lead-account-key的lead-id只能通过只读访问器获取,不能直接修改。在build-url方法里,你可以通过访问器封装转换逻辑(比如自动把数字类型的lead-id转换成字符串),而结构体的槽是公开可直接读写的,没法做这种逻辑封装。
内容的提问来源于stack exchange,提问作者Vinn

