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的编程习惯:
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

