如何在 Smalltalk 中访问二维数组中的元素
How to access an element in 2d array in Smalltalk
我开始使用 Smalltalk 编码,但卡在了这里。我有这个二维数组:
testArr := Array new: 1.
testArr at: 1
put: ((Array new: 3)
at: 1 put: '1A';
at: 2 put: '1B';
at: 3 put: '1C';
yourself).
但是如果我想访问第一个数组的第一个元素,我应该写什么来实现它?
谢谢!
所以,问题在括号中。
^(testArr at: 1) at:1
returns
1A
因为我需要。
我很想利用您的问答,详细阐述属于 Smalltalk 民间传说(您可能已经知道)的知识。
随着我们在使用 Smalltalk 方面取得进展,我们可能会注意到 Array
class 在我们的模型中开始发挥越来越小的作用。这是为什么?因为找出我们的模型将产生哪些对象需要时间;太多和太少之间的平衡是一件微妙的事情,一开始大多毫无头绪。
数组及其组合是方便的数据结构。但是,它们以处理数据为代价解决了组织数据的问题。如果这种结构的客户端需要知道数据是如何存储的作为对其进行操作的先决条件,那么消息范式在语义上就变得空闲了。
让我们想象一个矩阵对象。有几种方法可以保留它们的条目:一维数组、行数组、列数组、(稀疏)非空条目的字典、三角形结构(如果矩阵已知为 symmetric/anti-symmetric/Hermitian,还有更多的特殊情况。当然,这种多样性对于手头的问题没有任何意义,无论如何,花时间考虑最通用的方法是一个坏主意:在 Smalltalk 中,通用性是在消息中获得的,而不是在仓库。
无论数据的内部组织如何,我们的对象都应该始终提供独立于底层结构的协议。回到矩阵示例,即使我们的初始组织是行数组,矩阵对象也应该工作相同,无论行是数组还是更复杂的 vector 对象也用于其他目的.这意味着在对条目 (i,j)
的内部访问进行编码时,我们应该假装我们不知道行 i
的 class,而只知道访问其第 j
元素的消息.类似
的东西
atRow: i column: j
| row |
row := self row: i.
^row at: j
这里我们不假设row
是一个Array
;我们只是假设它理解 at:
消息,这是我们在与行对象交谈时至少可以假设的,无论其实际性质如何。当然,此代码仅在假设行不会即时重新创建的情况下才有用,如果我们的 class 保留列的集合,它们就会这样做。但这没关系,否则我们只需要添加另一个 class 并覆盖它和其他一些 low level 消息。
无论如何,我们的想法是尽可能推迟任何关于内部组织的明确知识,以便将其限制在一些私人消息中。测试我们是否应用这种良好做法的一种方法是确保没有低级代码在两种或多种方法中重复。例如,使用上面的 row:
消息将低级代码从 atRow:column:
移开,将其推迟到另一个对(理想)矩阵协议有意义的代码。
这个例子说明了一个要点:对任何需要组成两条 at:
消息的代码都要持怀疑态度。并且 - 为什么不 - 享受不必声明类型的美妙。
我开始使用 Smalltalk 编码,但卡在了这里。我有这个二维数组:
testArr := Array new: 1.
testArr at: 1
put: ((Array new: 3)
at: 1 put: '1A';
at: 2 put: '1B';
at: 3 put: '1C';
yourself).
但是如果我想访问第一个数组的第一个元素,我应该写什么来实现它?
谢谢!
所以,问题在括号中。
^(testArr at: 1) at:1
returns
1A
因为我需要。
我很想利用您的问答,详细阐述属于 Smalltalk 民间传说(您可能已经知道)的知识。
随着我们在使用 Smalltalk 方面取得进展,我们可能会注意到 Array
class 在我们的模型中开始发挥越来越小的作用。这是为什么?因为找出我们的模型将产生哪些对象需要时间;太多和太少之间的平衡是一件微妙的事情,一开始大多毫无头绪。
数组及其组合是方便的数据结构。但是,它们以处理数据为代价解决了组织数据的问题。如果这种结构的客户端需要知道数据是如何存储的作为对其进行操作的先决条件,那么消息范式在语义上就变得空闲了。
让我们想象一个矩阵对象。有几种方法可以保留它们的条目:一维数组、行数组、列数组、(稀疏)非空条目的字典、三角形结构(如果矩阵已知为 symmetric/anti-symmetric/Hermitian,还有更多的特殊情况。当然,这种多样性对于手头的问题没有任何意义,无论如何,花时间考虑最通用的方法是一个坏主意:在 Smalltalk 中,通用性是在消息中获得的,而不是在仓库。
无论数据的内部组织如何,我们的对象都应该始终提供独立于底层结构的协议。回到矩阵示例,即使我们的初始组织是行数组,矩阵对象也应该工作相同,无论行是数组还是更复杂的 vector 对象也用于其他目的.这意味着在对条目 (i,j)
的内部访问进行编码时,我们应该假装我们不知道行 i
的 class,而只知道访问其第 j
元素的消息.类似
atRow: i column: j
| row |
row := self row: i.
^row at: j
这里我们不假设row
是一个Array
;我们只是假设它理解 at:
消息,这是我们在与行对象交谈时至少可以假设的,无论其实际性质如何。当然,此代码仅在假设行不会即时重新创建的情况下才有用,如果我们的 class 保留列的集合,它们就会这样做。但这没关系,否则我们只需要添加另一个 class 并覆盖它和其他一些 low level 消息。
无论如何,我们的想法是尽可能推迟任何关于内部组织的明确知识,以便将其限制在一些私人消息中。测试我们是否应用这种良好做法的一种方法是确保没有低级代码在两种或多种方法中重复。例如,使用上面的 row:
消息将低级代码从 atRow:column:
移开,将其推迟到另一个对(理想)矩阵协议有意义的代码。
这个例子说明了一个要点:对任何需要组成两条 at:
消息的代码都要持怀疑态度。并且 - 为什么不 - 享受不必声明类型的美妙。