You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pharo中类方法引用类名而非self class的警告及报错咨询

嘿,刚接触Pharo和Smalltalk对吧?这个问题其实是Smalltalk里类方法与元类的基础概念没捋清楚,我来给你掰扯明白~

问题根源拆解

首先得搞懂两个核心点:

  • 你写的value: aValue unit: anUnit是类方法(挂在Amount class这个元类上的方法),在类方法里,self指的就是Amount这个类本身,不是Amount的实例。
  • Pharo给的警告“Refers to class name instead of "self class"”,本质是在提醒你:硬编码类名Amount不够灵活——万一以后有子类继承这个方法,硬编码会导致子类创建的还是Amount实例,而非子类自己的实例。

那为什么改成(self class) new会报错呢?因为在类方法里,self是Amount class(元类),self class就是Metaclass(元类的类)。而Smalltalk有个规则:每个元类只能有一个实例(就是对应的那个类,比如Amount),所以调用Metaclass new就会触发“A Metaclass should only have one instance!”的错误——就像你想给一个已经有唯一实例的类再创建新实例,当然行不通啦。

正确的写法

其实特别简单,把amount := Amount new改成amount := self new就行!因为类方法里的self就是Amount类本身,self new就是创建Amount的实例,完美解决警告和报错:

value: aValue unit: anUnit
    | amount |
    amount := self new .
    amount value: aValue ; unit: anUnit .
    ^ amount
额外的Smalltalk风格优化

你还可以把代码简化成链式调用,更符合Smalltalk的编程习惯:

value: aValue unit: anUnit
    ^ self new
        value: aValue;
        unit: anUnit;
        yourself

这里的yourself是为了确保返回的是刚创建的Amount实例(因为unit:方法可能返回的是anUnit,而我们要返回的是实例本身)。

为什么这样更优

假设以后你创建了Amount的子类EuroAmount,这个类方法会被继承过去。调用EuroAmount value: 10 unit: 'EUR'时,self就是EuroAmount,会自动创建EuroAmount的实例,而不是硬编码的Amount实例——这就是Smalltalk多态的体现,也是Pharo警告你不要硬编码类名的核心原因。

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:44:31