在 GNU Smalltalk 中使用和不使用 `new` 创建的实例之间的区别
Difference between instances created with and without `new` in GNU Smalltalk
有什么区别
Rectangle origin: 5@5 extent: 40@30
和
Rectangle new origin: 5@5 extent: 40@30
这是风格问题。 Rectangle class 提供了一个创建实例的便利方法,这样您就可以直接与 class 通信并编写更少的代码。这也是一个很好的做法,因为您创建矩形对象时需要它正常工作(这种做法称为 RAII,资源获取是初始化)。如果您查看 Rectangle class>>#origin:extent:
的源代码,您会发现非常类似于
的内容
origin: aPoint extent: anotherPoint
^self new origin: aPoint extent: anotherPoint
所以实际上将消息直接发送到 class o 手动创建然后设置它实际上是相同的
Rectangle new origin: 5@5 extent: 40@30
创建一个完全初始化的 Rectangle 实例(准确地说,所有坐标都设置为 0),然后使用 origin:extend: 访问器方法设置其坐标和范围。
Rectangle origin: 5@5 extent: 40@30
有 class Rectangle 构造一个具有给定属性的 Rectangle 实例,但它认为合适。对于 GNU Smalltalk,它使用 basicNew 消息来分配 Rectangle 实例而不是 new (see the source of Rectangle)。这放弃了上面变体的 "fully-initialized instance" 状态:它跳过任何初始化并只分配内存(好吧,GNU Smalltalk 文档没有这么明确地说,但这通常是 basicNew 的目的)。然后它使用 origin:extend: 访问器来初始化新实例的坐标和范围。
我认为重要的是要注意 Smalltalk 和其他 OO 语言之间的区别。
在其他 OO 语言中,您有一个称为构造函数的结构。这使您能够在调用方法 new
.
时自动 运行 某些代码
例如,在ruby中你会做
# Class name
class ConstructorExample
# A constructor
def initialize
puts "I'm now running constructor"
end
end
# Creating Object
ConstructorExample.new # upon which calling you will get initialized run automatically.
输出将在您的 shell:
> I'm now running constructor
在Smalltalk中你必须区分new
和basicNew
。 (有时甚至 new
只是 basicNew
的别名,因此您必须手动 运行 initialize
或创建 class 方法。 basicNew
不会自动执行初始化,new
通常会执行(不是所有方言!)。
上面的例子可以写成:
Object subclass:#ConstructorExample
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
category: ''
ConstructorExample>>initialize
Transcript showCR: 'I'm now running a constructor'
"You would then instantiate"
ConstructorExample new
或
| example |
example := ConstructorExample basicNew.
example initialize "sending method initialize like any other method"
在这两种情况下,输出都是(在您的成绩单中):
I'm now running a constructor
在我看来,这样做的主要原因是,如果您有 class 方法
,您可以在一些自定义代码之后 运行 构造函数
ConstructorExample class >> run
^ self basicNew; Transcript showCR: 'Running before constructor'; self initialize; yourself
那么你只需要做:
ConstructorExample run
输出将是:
Running before constructor
I'm now running a constructor
现在举个例子
正如 JayK、melkyades 解释的主要差异一样,我将给出更多关于这些的细微差异(细节):
第一个:
Rectangle new origin: 5@5 extent: 40@30
它实际上做了什么(没有 Transcript showCR:
):
| myRactangle |
myRactangle := Ractangle new. "Creates an empty instance with origin: 0 @ 0 corner: 0 @ 0 and would execute initialize if there would be one."
Transcript showCR: 'Current origin: ', origin asString, 'with corner: ', corner asString. "You should see the zeros"
myRactangle origin: 5@5 extent: 40@30
Transcript showCR: 'Current origin: ', origin asString, 'with corner: ', corner asString. "You should your custom point(s)"
当你这样做时会发生什么Ractangle new
?
Rectangle class >> new [
"Answer the (0 @ 0 corner: 0 @ 0) rectangle"
<category: 'instance creation'>
^self origin: 0 @ 0 corner: 0 @ 0
]
当您检查源代码时,它 sets origin: 0 @ 0 corner: 0 @ 0
(注意通过...corner:
而非 extent:
进行设置的区别)。
第二个:
Rectangle origin: 5@5 extent: 40@30
源代码:
Rectangle class >> origin: originPoint extent: extentPoint
"Answer a rectangle with the given origin and size"
<category: 'instance creation'>
^self basicNew origin: originPoint corner: originPoint + extentPoint
正如所指出的那样,已经有一个 basicNew
可以防止任何 initialize
构造函数手动或通过 class 方法成为 运行,就像我上面显示的那样。
如果需要,您可以重写它。您将创建自己的矩形 class,它将从 Rectangle 继承并在那里重写。
例如:
Rectangle subclass:#ApplicationRectangle
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
category: ''
您要定义的位置:
ApplicationRectangle class >> origin: originPoint extent: extentPoint
"Answer a rectangle with the given origin and size"
<category: 'instance creation'>
^self new origin: originPoint corner: originPoint + extentPoint
你会称它为:
ApplicationRectangle origin: 5@5 extent: 40@30
有什么区别
Rectangle origin: 5@5 extent: 40@30
和
Rectangle new origin: 5@5 extent: 40@30
这是风格问题。 Rectangle class 提供了一个创建实例的便利方法,这样您就可以直接与 class 通信并编写更少的代码。这也是一个很好的做法,因为您创建矩形对象时需要它正常工作(这种做法称为 RAII,资源获取是初始化)。如果您查看 Rectangle class>>#origin:extent:
的源代码,您会发现非常类似于
origin: aPoint extent: anotherPoint
^self new origin: aPoint extent: anotherPoint
所以实际上将消息直接发送到 class o 手动创建然后设置它实际上是相同的
Rectangle new origin: 5@5 extent: 40@30
创建一个完全初始化的 Rectangle 实例(准确地说,所有坐标都设置为 0),然后使用 origin:extend: 访问器方法设置其坐标和范围。
Rectangle origin: 5@5 extent: 40@30
有 class Rectangle 构造一个具有给定属性的 Rectangle 实例,但它认为合适。对于 GNU Smalltalk,它使用 basicNew 消息来分配 Rectangle 实例而不是 new (see the source of Rectangle)。这放弃了上面变体的 "fully-initialized instance" 状态:它跳过任何初始化并只分配内存(好吧,GNU Smalltalk 文档没有这么明确地说,但这通常是 basicNew 的目的)。然后它使用 origin:extend: 访问器来初始化新实例的坐标和范围。
我认为重要的是要注意 Smalltalk 和其他 OO 语言之间的区别。
在其他 OO 语言中,您有一个称为构造函数的结构。这使您能够在调用方法 new
.
例如,在ruby中你会做
# Class name
class ConstructorExample
# A constructor
def initialize
puts "I'm now running constructor"
end
end
# Creating Object
ConstructorExample.new # upon which calling you will get initialized run automatically.
输出将在您的 shell:
> I'm now running constructor
在Smalltalk中你必须区分new
和basicNew
。 (有时甚至 new
只是 basicNew
的别名,因此您必须手动 运行 initialize
或创建 class 方法。 basicNew
不会自动执行初始化,new
通常会执行(不是所有方言!)。
上面的例子可以写成:
Object subclass:#ConstructorExample
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
category: ''
ConstructorExample>>initialize
Transcript showCR: 'I'm now running a constructor'
"You would then instantiate"
ConstructorExample new
或
| example |
example := ConstructorExample basicNew.
example initialize "sending method initialize like any other method"
在这两种情况下,输出都是(在您的成绩单中):
I'm now running a constructor
在我看来,这样做的主要原因是,如果您有 class 方法
,您可以在一些自定义代码之后 运行 构造函数ConstructorExample class >> run
^ self basicNew; Transcript showCR: 'Running before constructor'; self initialize; yourself
那么你只需要做:
ConstructorExample run
输出将是:
Running before constructor
I'm now running a constructor
现在举个例子
正如 JayK、melkyades 解释的主要差异一样,我将给出更多关于这些的细微差异(细节):
第一个:
Rectangle new origin: 5@5 extent: 40@30
它实际上做了什么(没有 Transcript showCR:
):
| myRactangle |
myRactangle := Ractangle new. "Creates an empty instance with origin: 0 @ 0 corner: 0 @ 0 and would execute initialize if there would be one."
Transcript showCR: 'Current origin: ', origin asString, 'with corner: ', corner asString. "You should see the zeros"
myRactangle origin: 5@5 extent: 40@30
Transcript showCR: 'Current origin: ', origin asString, 'with corner: ', corner asString. "You should your custom point(s)"
当你这样做时会发生什么Ractangle new
?
Rectangle class >> new [
"Answer the (0 @ 0 corner: 0 @ 0) rectangle"
<category: 'instance creation'>
^self origin: 0 @ 0 corner: 0 @ 0
]
当您检查源代码时,它 sets origin: 0 @ 0 corner: 0 @ 0
(注意通过...corner:
而非 extent:
进行设置的区别)。
第二个:
Rectangle origin: 5@5 extent: 40@30
源代码:
Rectangle class >> origin: originPoint extent: extentPoint
"Answer a rectangle with the given origin and size"
<category: 'instance creation'>
^self basicNew origin: originPoint corner: originPoint + extentPoint
正如所指出的那样,已经有一个 basicNew
可以防止任何 initialize
构造函数手动或通过 class 方法成为 运行,就像我上面显示的那样。
如果需要,您可以重写它。您将创建自己的矩形 class,它将从 Rectangle 继承并在那里重写。
例如:
Rectangle subclass:#ApplicationRectangle
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
category: ''
您要定义的位置:
ApplicationRectangle class >> origin: originPoint extent: extentPoint
"Answer a rectangle with the given origin and size"
<category: 'instance creation'>
^self new origin: originPoint corner: originPoint + extentPoint
你会称它为:
ApplicationRectangle origin: 5@5 extent: 40@30