如何在smalltalk中为实例变量指定class
How to specify class for instance variable in smalltalk
可能是我对smalltalk的概念了解不够,但是我的问题是:
我正在创建一个 class,我们称它为 Main-class,它有一个实例变量 bar,我想成为某个 class - Other-class,并使用这个 Other-class ' Main-class 方法中的方法有点像这样:
Object subclass: #Other-class
instanceVariableNames: 'foo'
classVariableNames: ''
poolDictionaries: ''
category: 'Custom-class'
setFoo: newFoo
foo := newFoo.
和 Main-class :
Object subclass: #Main-class
instanceVariableNames: 'bar'
classVariableNames: ''
poolDictionaries: ''
category: 'Custom-class'
newBar: val
bar := Bar new.
bar setFoo: val.
显然,我得到一个错误,提示没有 setFoo 方法。
但是我如何指定我希望 bar 成为特定 class 的变量,然后在其上使用 class' 方法?
关于问题的标题:你不知道。 Smalltalk 是一种动态类型语言,这意味着一个变量的值在不同的时间点可以有不同的类型——没有为变量声明类型。但对于人类,您可以在 class 注释中注明变量的实际类型(请参阅系统浏览器中 instance-side 和 class-side 按钮旁边的 ? 按钮)。
关于您的问题:您必须确保分配给实例变量 bar
的 object 是合适的类型。在这种情况下,它必须理解消息 setFoo:
。在您的第二个代码片段中,这意味着:
- 你应该使用另一个可以响应
setFoo:
的 class 而不是 Bar
,例如 Other-class
(顺便说一句,这是一个奇怪的名字,因为连字符,您不能在您的方法中轻松引用它,请改用 CamelCase) 来填充变量,或
setFoo:
必须为 class Bar
实施。
respondsTo:
方法可用于确定对象是否响应消息:
bar respondsTo: #setFoo
ifTrue: [bar setFoo: val]
ifFalse: [missiles launch]
如果您不想在 bar
不理解 setFoo
时发射导弹,那么请决定您想要发生什么。也许您的程序应该因错误而崩溃。这不像发射导弹那么极端,但仍然有点极端,而且很少是你真正想要的,特别是如果 其他人正在使用你的软件。
选项:只需使用正确的对象类型
ifFalse: [bar := ClassWithSetFoo new; setFoo: val]
选项:通过修改其 Class
来扩展对象以执行您需要的操作
ifFalse: [ (bar class) addInstVarName: 'foo'.
(bar class) compile: 'setFoo: newFoo [foo := newFoo]'.
bar setFoo: val. ]
第二个选项可能是也可能不是您想要的,具体取决于上下文。即使不是,它也说明了 Smalltalk 动态类型的强大功能。 Rails 上 Ruby 的大量 "magic" 是使用类似的策略构建的。这是可能的,因为 Ruby 对象与 Smalltalk 的对象在哲学上有很多相似之处。
可能是我对smalltalk的概念了解不够,但是我的问题是:
我正在创建一个 class,我们称它为 Main-class,它有一个实例变量 bar,我想成为某个 class - Other-class,并使用这个 Other-class ' Main-class 方法中的方法有点像这样:
Object subclass: #Other-class
instanceVariableNames: 'foo'
classVariableNames: ''
poolDictionaries: ''
category: 'Custom-class'
setFoo: newFoo
foo := newFoo.
和 Main-class :
Object subclass: #Main-class
instanceVariableNames: 'bar'
classVariableNames: ''
poolDictionaries: ''
category: 'Custom-class'
newBar: val
bar := Bar new.
bar setFoo: val.
显然,我得到一个错误,提示没有 setFoo 方法。 但是我如何指定我希望 bar 成为特定 class 的变量,然后在其上使用 class' 方法?
关于问题的标题:你不知道。 Smalltalk 是一种动态类型语言,这意味着一个变量的值在不同的时间点可以有不同的类型——没有为变量声明类型。但对于人类,您可以在 class 注释中注明变量的实际类型(请参阅系统浏览器中 instance-side 和 class-side 按钮旁边的 ? 按钮)。
关于您的问题:您必须确保分配给实例变量 bar
的 object 是合适的类型。在这种情况下,它必须理解消息 setFoo:
。在您的第二个代码片段中,这意味着:
- 你应该使用另一个可以响应
setFoo:
的 class 而不是Bar
,例如Other-class
(顺便说一句,这是一个奇怪的名字,因为连字符,您不能在您的方法中轻松引用它,请改用 CamelCase) 来填充变量,或 setFoo:
必须为 classBar
实施。
respondsTo:
方法可用于确定对象是否响应消息:
bar respondsTo: #setFoo
ifTrue: [bar setFoo: val]
ifFalse: [missiles launch]
如果您不想在 bar
不理解 setFoo
时发射导弹,那么请决定您想要发生什么。也许您的程序应该因错误而崩溃。这不像发射导弹那么极端,但仍然有点极端,而且很少是你真正想要的,特别是如果 其他人正在使用你的软件。
选项:只需使用正确的对象类型
ifFalse: [bar := ClassWithSetFoo new; setFoo: val]
选项:通过修改其 Class
来扩展对象以执行您需要的操作ifFalse: [ (bar class) addInstVarName: 'foo'.
(bar class) compile: 'setFoo: newFoo [foo := newFoo]'.
bar setFoo: val. ]
第二个选项可能是也可能不是您想要的,具体取决于上下文。即使不是,它也说明了 Smalltalk 动态类型的强大功能。 Rails 上 Ruby 的大量 "magic" 是使用类似的策略构建的。这是可能的,因为 Ruby 对象与 Smalltalk 的对象在哲学上有很多相似之处。