我知道比Java和Ruby更动态的Java语言通常允许您将混合类型的对象放在数组中,如下所示:
1
| ["hello", 120, ["world"]] |
我不明白为什么你会使用这样的功能。如果我想在Java中存储异构数据,我通常会为它创建一个对象。
例如,假设User具有int ID和String name。虽然我在Python / Ruby / PHP中看到你可以这样做:
1
| [["John Smith", 000], ["Smith John", 001], ...] |
这似乎比创建一个属性ID和name的类User然后拥有你的数组更安全/ OO:
1
| [<User: name="John Smith", id=000>, <User: name="Smith John", id=001>, ...] |
其中事物代表用户对象。
是否有理由在支持它的语言中使用前者而不是后者?或者是否有更大的理由使用异构数组?
注:我不是在讨论包含所有实现相同接口或从同一父接口继承的不同对象的数组,例如:
1 2 3
| class Square extends Shape
class Triangle extends Shape
[new Square (), new Triangle ()] |
因为对于程序员而言,至少仍然是一个同质数组,因为你将对每个形状做同样的事情(例如,调用draw()方法),只有两者之间通常定义的方法。
-
Python或Ruby是动态类型的,因此异构数组是"免费"实现的。
-
"这似乎不太安全"?"安全"是什么意思?请注意,"类型安全"是Python中的绝对保证,因为对象的类型与某些方式无法通过类似转换操作撤消的方式耦合。请在此问题中定义"安全"的含义。
-
一种安全性是在编译时检测到编码错误。这是动态类型语言不能提供多种错误的东西。当然,您可以获得灵活性。
-
安全,就像我知道每个元素都有一个名称和ID通过构造函数 - 我的程序的某些部分不会在我不知情的情况下意外地粘贴["Smith John", 000,"[email protected]"。
-
除非你告诉它首先做到这一点,否则该计划将如何贴上这样的东西呢?
-
@aharon"我的程序的某些部分不会在我不知情的情况下偶然发现["Smith John", 000,"[email protected]" - 所以你永远不会犯错误?你和每个与你一起工作这个代码的人总是按照他们应该调用的方式调用函数,所有的参数都按照正确的顺序排列?我无法相信这就是你的建议,但这听起来像是,我不确定你在说什么。
-
不 - 我说是因为我确实犯了错误,能够使用( (String) name, (int) id )形式的构造函数的对象允许语言在有人编码不正确时发送错误,例如name, id, email。
-
@aharon:"允许语言在有人编码错误时发送错误"不是真的。您可以轻松地创建一个具有正确构造函数的类,该构造函数仍然表现不佳,因为方法实现不正确。
正如katrielalex写道:没有理由不支持异构列表。事实上,不允许它需要静态打字,我们回到那个古老的辩论。但是,我们不要这样做,而是回答"为什么要使用那个"部分......
说实话,它没有那么多使用 - 如果我们在你的最后一段中使用异常并选择一个更自由的定义"实现相同的接口"而不是例如Java或C#。几乎所有我的可迭代代码都希望所有项都能实现一些接口。当然它确实如此,否则它可以做很少的事情!
不要误会我的意思,有绝对有效的用例 - 很少有理由写一个完整的类来包含一些数据(即使你添加一些callables,函数式编程有时也会拯救)。虽然dict是一个更常见的选择,而且namedtuple也非常简洁。但它们并不像你想象的那么普遍,它们被用于思想和纪律,而不是用于牛仔编码。
(另外,你"User作为嵌套列表"的例子不是一个好例子 - 因为内部列表是固定大小的,你最好使用元组,即使在Haskell中它也有效(类型将是[(String, Integer)]))
-
这些"绝对有效的用例"是什么?
-
@aharon:几乎每次他们工作时都比其他选择更麻烦。例如,具有异构值的dicts(问题是关于数组,但实际上任何集合都可以是异构的)构成良好的轻量级类。异构元组/列表不太自我记录,因此不太合适,但也取决于数据有效(例如,在太少的地方使用太少的数据使得字典特别优越)。
-
我知道它是多年以后,但是:对我来说,JavaScript中的常见用例是arguments,将其转换为(异构)数组,弹出/移动一些参数,然后使用.apply()。在编写事件处理库(.on(),.off())或编写包装/提升/修改其他函数的函数时,我经常使用它。
将多方法应用于数组可能有一定道理。您可以将策略切换到更具功能性的样式,在该样式中您可以专注于离散的逻辑片段(即多方法),而不是离散的数据片段(即数组对象)。
在形状示例中,这可以防止您必须定义和实现Shape接口。 (是的,这不是什么大问题,但如果形状是你想要扩展的几个超类之一呢?在Java中,你现在是SOL。)相反,你实现了一个智能的draw()多方法,首先检查如果对象不可绘制,则参数然后调度到正确的绘图功能或错误处理。
功能和面向对象风格之间的比较到处都是;这里有几个相关的问题应该提供一个良好的开端:功能编程与面向对象的编程和向面向对象的程序员和技术人员解释函数式编程。
-
@aharon关于功能性与面向对象编程的最后一段是为了一般的好处,无论是谁在阅读这个答案。我并不是说你没有意识到这些差异。
Is there reason to use the former over
the latter in languages that support
it?
是的,有一个非常简单的原因可以让你在Python中做到这一点(我在Ruby中假设相同的原因):
你如何检查列表是异质的?
-
它不能直接比较类型,因为Python有鸭子打字。
-
如果所有对象都有一些常见的类型类,Python也无法猜测。无论如何,一切都支持repr,所以你也应该能够将它们放在一个列表中。
-
将列表转换为需要类型声明的唯一类型也没有任何意义。
根本没有办法阻止你创建一个异类列表!
Or is there some bigger reason to use
heterogenous arrays?
不,我想不出任何。正如您在问题中已经提到的那样,如果您使用异构数组,那么您只是将事情变得更加艰难。
没有理由不支持异构列表。这是技术原因的限制,我们不喜欢这些。
并非一切都需要成为一个班级!
在Python中,一个类基本上是一个带有一些额外内容的加强字典。因此,使类?x0>不一定比字典{"name": ...,"id": ...}更清晰。
-
但是如果我想稍后扩展它们,那么字典就没有额外的方法,对吧?
-
不,但如果你想要额外的方法,你可以继承dict。这是可扩展的;您可以将字典与FunkyDictionaries和自定义映射混合和匹配,只要在运行代码时,您需要的所有方法都在那里。另请注意,您可以拥有全局函数(不附加到类),因此您可以定义函数split_name = lambda d: d['name'].split()以返回由空格分隔的名字和姓氏。并且此函数不必与dict类关联。
-
@aharon:如果你想要自定义方法,即真实行为,则保证一个类。但是,如果你只是想构建一些数据并对它应用转换,那就不是了 - 对于这些(非常常见的)情况,一个类增加了零益处和太多的额外行。
没有什么可以阻止你在Java中使用异构数组。它被认为是糟糕的编程风格,并且使用适当的POJO将比Java或任何其他语言中的异构数组更快/更有效,因为"字段"的类型是静态已知的并且可以使用原语。
在Java中你可以
1
| Object[][] array = {{"John Smith", 000 }, {"Smith John", 001 }, ... }; |
在Lua中,对象和数组是相同的,所以原因更清楚。让我们说Lua将弱打字变为极端
除此之外,我有一个谷歌地图对象,我需要删除到目前为止在该地图中创建的所有标记。所以我最终为markers创建了一个数组,一个circles的数组和一个places的数组。然后我创建了一个迭代这三个数组的函数,并在每个数组上调用.remove()。然后我意识到我可以只有一个非同类数组并将所有对象插入其中并在该数组上迭代一次
Eterogenous列表非常有用。例如,为了制作蛇游戏,我可以有一个像这样的块列表:
[[x,y,'down'],[x1,y1,'down']]
而不是块的类,我可以更快地访问每个元素。
-
它仍然是(int,int,string)元组的同类列表。
-
但int,int,string是异构的。
-
我不会在概念上将您的内部列表视为异构列表,而是将其视为3元组。但当然,在动态类型语言中,它由相同类型支持。但是在静态类型语言中,您可以使用元组实现相同的功能而不会丢失(编译时)类型安全性。因此,除了静态类型语言提供的内容之外,显示异构列表的用途并不是一个好例子。
-
"我可以更快地访问每个元素。" [引证需要]
-
@MatrixFrog:pastebin.com/10DCvtuQ这个小片段,在我的电脑上,输出:6.58470416069 6.20616889
-
@pythonFoo。我承认我很惊讶。我想也许有一些奇怪的优化正在进行所以我稍微修改了一下:gist.github.com/755616即使有了这个改变,阵列访问仍然更快。
-
我认为这是因为对象(基本上只是dicts)被设计为在有很多字段时可以快速访问,但他们并没有花太多时间担心只有几个字段的情况,所以有一点点在这种情况下,一点点开销会减慢你的速度。
这是一个简单的答案:
N.B. I am not talking about arrays that include different objects that
all implement the same interface or inherit from the same parent, e.g.:
BLOCKQUOTE>
一切都扩展了java.lang.Object ......而且这很多。没有理由不使用Object []并放置任何你喜欢的东西.Object []在持久层等任何中间件中都非常有用。
-
-1。如果您正在使用Java,那么您也可以利用其编译时类型检查。任何使用Object或Object[]的代码都会立刻引发一个红旗。