Smalltalk 如何在超类方法中从子类调用块?

Smalltalk 如何在超类方法中从子类调用块?,smalltalk,gnu-smalltalk,Smalltalk,Gnu Smalltalk,我认为我的问题主要是语法,但可能是我对类层次结构的总体理解。基本上它是一个卡片类,有一个充满卡片对象的数组,卡片是卡片的一个子类,所以卡片应该能够使用卡片的块和方法,对吗?如果是这样的话,我在尝试调用它时就把语法搞乱了。我使用嵌套的while循环来填充数组,但我希望Card对象的每个实例都具有该卡的套色和等级,而不仅仅是打印一张卡。我离开的地方,我试图使卡对象的另一个数组大小为2,以容纳西装和排名,但我的gst编译器说,它期待一个对象,所以很明显,我做错了什么。我粘贴了我的代码,所以你可以看到我

我认为我的问题主要是语法,但可能是我对类层次结构的总体理解。基本上它是一个卡片类,有一个充满卡片对象的数组,卡片是卡片的一个子类,所以卡片应该能够使用卡片的块和方法,对吗?如果是这样的话,我在尝试调用它时就把语法搞乱了。我使用嵌套的while循环来填充数组,但我希望Card对象的每个实例都具有该卡的套色和等级,而不仅仅是打印一张卡。我离开的地方,我试图使卡对象的另一个数组大小为2,以容纳西装和排名,但我的gst编译器说,它期待一个对象,所以很明显,我做错了什么。我粘贴了我的代码,所以你可以看到我在说什么。除了块调用之外,它正在用空白卡片对象填充一个大小为52的数组,因此Deck类的其余部分基本上可以工作

"The Deck object class is a deck of 52 Card objects. "
Object subclass: Deck [
    | Content |
        <comment: 'I represent of Deck of Cards'>
    Deck class >> new [
        <category: 'instance creation'>
        | r |
        r := super new . 
        Transcript show: 'start ' .
        r init .
        ^r
    ] 

    init [
        <category: 'initialization'>

        |a b c|
        Content := Array new: 52 .
        a := 1 .
        c := 1 . 



        [a <= 4] whileTrue:[
            b := 1 . 
            [b <= 13] whileTrue:[
                |card|
                card := Card new .
                Card := Array new: 2 .            "This is where I'm trying to use the Card class blocks to make the Card objects have Rank and Suit" 
                Card at: 1 put: Card setRank: b| . "and here the rank"
                Card at: 2 put: Card getSuit: a| . "and the suit"
                Content at: c put: card .

                b := b + 1 .
                c := c + 1 . 

            ].

            a := a + 1 . 

        ].
     Content printNl . 
    ]

] .

"The Card object has subclass Suit and a FaceValue array of Suit and Rank. "
Object subclass: Card [
    | Suit Rank |
        <comment: 'I represent a playing Card' >
    init [
        <category: 'initialization'>
        Suit := Club .
        Rank := 1 .
        Transcript show: 'nCard ' .
        ^super init
    ]
    getSuit: suitVal [
        suitVal = 1 ifTrue: [Suit := Club] . 
        suitVal = 2 ifTrue: [Suit := Diamond] . 
        suitVal = 3 ifTrue: [Suit := Heart] . 
        suitVal = 4 ifTrue: [Suit := Spade] . 
        ^Suit 
    ] "getSuit"

    setRank: rankVal [
    Rank := rankVal . 
    ^Rank
    ]
] 

z := Deck new .
编辑一次-由于fede s.的评论

欢迎来到SO

免责声明:我使用的Smalltalk/X-jv分支与gnu Smalltalk不同,所以我不是gnu Smalltalk专家

我会指出我发现的一些不足之处。有太多的东西要指出。我会给你一些大概的想法

我一般不建议使用a,b,c。。。z作为变量。如果您稍后返回代码,您将无法理解它

对于变量,请使用类似小写的内容,而不是内容。第一 大写字母保留给全局变量。在您的用例中,这将是一个类名,不要混用它

如果要创建一个新实例,请按如下方式使用:aCard:=Card new

不要在init initialize方法中创建整个应用程序逻辑!您应该将代码分解为小的、可读的方法

您的init应该沿着以下几行进行查看:

  Deck extend [
      init [
          <category: 'initialization'>
          content := Array new: 52.
          Transcript show: 'Initializing Deck...'.
      ]
  ]
有充分的理由重新定义新消息。抄本消息可以是ini init:

你为什么要重新定义新概念?如果您有一个对象是对象子类:那么 已经理解了新的信息

在代码的底部有z:=Deck new。我建议使用例如myDeck:=Deck new。。如果您想运行initialize,只需执行myDeck init

为什么您在Card>>init返回^super init?也许您想执行第一行超级初始化读取\加载超类初始化,然后返回^self?很难说

西服:=俱乐部。这是什么意思?您是否正在以某种方式创建一个新对象?缺少新消息。你是在试着解开一根绳子吗?它应该是suit:=“俱乐部”。然后所有Sunit变量分配也是如此

更多的是阅读水晶球。尝试阅读更多有关Smalltalk的信息,我希望我的提示能对您有所帮助。

编辑一次-由于fede s.的评论

欢迎来到SO

免责声明:我使用的Smalltalk/X-jv分支与gnu Smalltalk不同,所以我不是gnu Smalltalk专家

我会指出我发现的一些不足之处。有太多的东西要指出。我会给你一些大概的想法

我一般不建议使用a,b,c。。。z作为变量。如果您稍后返回代码,您将无法理解它

对于变量,请使用类似小写的内容,而不是内容。第一 大写字母保留给全局变量。在您的用例中,这将是一个类名,不要混用它

如果要创建一个新实例,请按如下方式使用:aCard:=Card new

不要在init initialize方法中创建整个应用程序逻辑!您应该将代码分解为小的、可读的方法

您的init应该沿着以下几行进行查看:

  Deck extend [
      init [
          <category: 'initialization'>
          content := Array new: 52.
          Transcript show: 'Initializing Deck...'.
      ]
  ]
有充分的理由重新定义新消息。抄本消息可以是ini init:

你为什么要重新定义新概念?如果您有一个对象是对象子类:那么 已经理解了新的信息

在代码的底部有z:=Deck new。我建议使用例如myDeck:=Deck new。。如果您想运行initialize,只需执行myDeck init

为什么您在Card>>init返回^super init?也许您想执行第一行超级初始化读取\加载超类初始化,然后返回^self?很难说

西服:=俱乐部。这是什么意思?您是否正在以某种方式创建一个新对象?缺少新消息。你是在试着解开一根绳子吗?它应该是suit:=“俱乐部”。然后所有Sunit变量分配也是如此


更多的是阅读水晶球。尝试阅读更多关于Smalltalk的内容,我希望我的提示能对您有所帮助。

一点更正:您不调用块,而是调用方法

您提交的代码中唯一的块是whileTrue:的参数,并且对于无法从外部访问的方法是私有的

这种混乱不是你的错。这是由于该文件格式用于描述方法的块表示法。就个人而言,我不喜欢它,我觉得它更混乱 除了看起来更像主流语言之外,这是对基于文件的语言的赞扬

那么如何调用一个方法呢?你通过发送信息来实现,没有其他方法。你所能做的就是发送一条消息。Smalltalk是面向消息的。一路下来都是信息

接收消息时,对象将在其类方法字典中查找消息选择器。如果没有,它将在超类中查找,等等。。。但那是物体自己的事

因此,在最后,您并不真正考虑调用方法,因为不同的对象可以使用不同的方法响应相同的消息。您必须考虑将任务委托给专门化对象,即消息和相关契约

那么合同是什么?你想要一张有西服俱乐部的卡片,斯派德。。。排名从1到13。因此,您使用这两个实例变量创建了一个Card类。到目前为止,一切顺利

然后你要创建52张牌来填充牌组。这是对Card类的实例化。你是怎么做到的?您已将新消息发送到Card类。您可以创建一个更合适的类消息,该类消息将充当一个卡片构造器,给定一套西装和一个等级

那大概是

Card class >> newWithSuit: aSuit rank: anInteger
    [<category: 'instance creation'>
    ^self basicNew setSuit: aSuit rank: anInteger ]

setSuit: aSuit rank: anInteger
    [<category: 'private'>
    suit := aSuit.
    rank := anInteger ]
请注意括号:您将消息发送到:put:to content,并使用两个参数deckRank和另一个消息发送卡newWithSuit:suitNumber rank:rankNumber返回的值,我们希望它是一个正确初始化的卡实例

在您提供的代码Card at:1 put:Card setRank:b中,您在:put:setRank:向类Card发送一条消息,其中包含3个参数:整数文本1、类Card和变量b指向的对象。那可能不是你的意图。在b后面还有一个条,我觉得它的语法不太正确。条形图用于描绘临时变量,或将块参数与块内的块指令分开,也可以是二进制消息,但在这种情况下需要一个参数每个二进制消息(如+-*/)都有一个接收器和一个参数


我希望我给了你一些有用的提示,但也许你必须阅读并应用一些循序渐进的Smalltalk教程来更好地了解这些基本概念。

一点更正:你不调用块,而是调用方法

您提交的代码中唯一的块是whileTrue:的参数,并且对于无法从外部访问的方法是私有的

这种混乱不是你的错。这是由于该文件格式用于描述方法的块表示法。就我个人而言,我不喜欢它,我发现它更令人困惑而不是有用,只是为了看起来更像主流语言,这是对基于文件的语言的赞扬

那么如何调用一个方法呢?你通过发送信息来实现,没有其他方法。你所能做的就是发送一条消息。Smalltalk是面向消息的。一路下来都是信息

接收消息时,对象将在其类方法字典中查找消息选择器。如果没有,它将在超类中查找,等等。。。但那是物体自己的事

因此,在最后,您并不真正考虑调用方法,因为不同的对象可以使用不同的方法响应相同的消息。您必须考虑将任务委托给专门化对象,即消息和相关契约

那么合同是什么?你想要一张有西服俱乐部的卡片,斯派德。。。排名从1到13。因此,您使用这两个实例变量创建了一个Card类。到目前为止,一切顺利

然后你要创建52张牌来填充牌组。这是对Card类的实例化。你是怎么做到的?您已将新消息发送到Card类。您可以创建一个更合适的类消息,该类消息将充当一个卡片构造器,给定一套西装和一个等级

那大概是

Card class >> newWithSuit: aSuit rank: anInteger
    [<category: 'instance creation'>
    ^self basicNew setSuit: aSuit rank: anInteger ]

setSuit: aSuit rank: anInteger
    [<category: 'private'>
    suit := aSuit.
    rank := anInteger ]
请注意括号:您将消息发送到:put:to content,并使用两个参数deckRank和另一个消息发送卡newWithSuit:suitNumber rank:rankNumber返回的值,我们希望它是一个正确初始化的卡实例

在您提供的代码Card at:1 put:Card setRank:b中,您在:put:setRank:向类Card发送一条消息,其中包含3个参数:整数文本1、类Card和变量b指向的对象。那可能不是你的意图。在b后面还有一个条,我觉得它的语法不太正确。条形图用于描绘临时变量,或将块参数与块内的块指令分开,也可以是二进制消息,但在这种情况下需要一个参数每个二进制消息(如+-*/)都有一个接收器和一个参数

我希望我给了你一些有用的提示,但也许你必须阅读并应用一些循序渐进的Smalltalk教程,以便更好地了解这些基本概念。

仅此而已
澄清一些事情,我非常确定我希望卡片组中充满卡片对象,因为这个项目要求我使用一些规则操纵卡片,根据颜色更改卡片的等级/套装。因此,我认为保持这种结构将使以后更容易做到这一点。否则,我可以用字符填充数组,使其看起来像卡片,但这样就不会是真正的卡片对象。卡不应该是卡组的子类,因为卡不是卡组,它只是卡组的一个元素。为了澄清一些事情,我非常确定我希望卡组充满卡对象,因为这个项目要求我使用一些规则操纵卡,根据颜色更改卡的等级/适合度。因此,我认为保持这种结构将使以后更容易做到这一点。否则,我可以用字符填充数组,使其看起来像卡片,但这样就不会是真正的卡片对象。卡不应该是牌组的子类,因为卡不是牌组,它只是它的一个元素,只是一个吹毛求疵的东西。Afaik,按照惯例,大写字母通常用于全局,其中类名是最扩展的用例。转录本iirc是一个全局实例,Smalltalk通常是SystemDictionary的唯一实例,还有一些其他实例。@fedes。是的,谢谢你添加它。我试图让ALW保持简单,但可能过于简单化了,只关注显示的代码。@fedes。我决定根据你的评论进行编辑。只是吹毛求疵。Afaik,按照惯例,大写字母通常用于全局,其中类名是最扩展的用例。转录本iirc是一个全局实例,Smalltalk通常是SystemDictionary的唯一实例,还有一些其他实例。@fedes。是的,谢谢你添加它。我试图让ALW保持简单,但可能过于简单化了,只关注显示的代码。@fedes。我决定根据你的评论进行编辑。
content at: deckRank put: (Card newWithSuit: suitNumber rank: rankNumber).