【问题标题】:How do I store the type of an object in a variable?如何将对象的类型存储在变量中?
【发布时间】:2019-05-03 15:26:33
【问题描述】:

我有一个需要传递元素类型的类,因此我可以稍后检查另一个对象是否具有该类型或者是该类型的子类并将其添加到内部集合中。

我有一个 initialize: 方法,该方法从我班级的 new: ctor 调用:

initialize: aType
    elements := OrderedCollection new.
    type := aType class.

现在我有一个方法可以传递一个值,并且应该检查类型是否兼容:

add: anElement  
    type isNil ifTrue: [ elements add:anElement. ^self. ].

    (anElement isMemberOf: type)
       ifTrue: [elements add:anElement.]
       ifFalse: [ ^ 'Not supported!' ].

如果我想检查具体类型,这很有效:

|myClass|
myClass:= MyClass new: '123'.

cc add: '5.4'. "Works"
cc add: 123.  "Fails correctly."

现在,为了检查它是否是派生类型,我修改了add:方法:

add: anElement  
    type isNil ifTrue: [ elements add:anElement. ^self. ].

    (anElement isKindOf: type)
      ifTrue: [elements add:anElement.]
      ifFalse: [ ^ 'Not supported!' ].

但是,这不起作用:

|myClass|
myClass:= MyClass new: 5 asNumber.

myClass add: 5.4. "Fails, although Float is a sub type of Number"

我怀疑我最初确定对象类型的方法 (aType class) 是错误的,但我找不到更好或更明确的确定类型的方法。基本上,我在 C# 中寻找类似 @​​987654330@ 的东西。这是练习的一部分,所以请原谅这个人为的例子:)

【问题讨论】:

  • 在最后一个示例中,您定义了myClass 变量,然后执行cc add: 5.4cc 是另一个变量。如果您在操场上执行此操作,cc 将被初始化为零。你得到什么错误?
  • 问题在于5 asNumber == 5SmallInteger 而不是Number。因此5.4 不是它的子类型。
  • @AndreiChis:感谢您提供的信息,这是我的复制/粘贴错误。它们应该是相同的。
  • 也许还可以考虑使用谓词(通过块),例如 MyClass restrictedTo: [:x | x isInteger and: [x > 0]] 包含其他可能性 MyClass restrictedTo: [:x | x isMemberOf: Character]MyClass restrictedTo: [:x | x isKindOf: Number]

标签: smalltalk pharo


【解决方案1】:

正如我在对您的问题的评论中提到的,问题在于 5 asNumber5,它是 SmallInteger 的一个实例,而不是 Number 的一个实例。因此,当您使用5 initialize: 您的班级时,您在 ivar type 中得到的是 SmallInteger。然后,当你add: 5.4时,校验变成5.4 isKindOf: SmallInteger,自然就失败了。

我认为问题出在您选择初始化实例的方式上。一种更简单的方法是使用类而不是实例显式设置目标type。有点像

initialize: aClass
  elements := OrderedCollection new.
  type := aClass

然后,您的示例将类似于

|myClass|
myClass:= MyClass new initialize: Number.
myClass add: 5.4.

它将接受5.4 作为一个元素,因为它是一个Float,它是isKindOf: Number

现在让我再补充一句。 new: 的常用语义与您使用的不同。 new: 的参数通常是 Integer 并且整数表示新实例的所需大小。例如,当您想要一个带有3 条目的Array 时,您说Array new: 3,等等。不希望new: 接收其他类型的用于构造对象的参数。我并不是说这是禁止的,只是这不是通常的命名约定。在您的情况下,我会建议一种创建实例的方法,例如

MyClass class >> on: aClass
  ^self new initialize: aClass

你的代码看起来像

| sequence |
sequence := MyClass on: Number.
sequence add: 5.                        "ok, 5 isKindOf: Number"
sequence add: 4.5.                      "ok, 5.4 isKindOf: Number"
sequence add: 'hello world'             "fail, not a Number"

【讨论】:

  • 也许像 MyCollection of: Number 而不是 on:?
猜你喜欢
  • 1970-01-01
  • 2022-01-24
  • 2012-07-10
  • 2018-09-23
  • 2012-02-05
  • 2021-03-10
  • 1970-01-01
相关资源
最近更新 更多