18

我是 Go 新手,但我读过 Go 常客不会错过参数多态性。每次我尝试学习一门新语言时,我都会使用L99 问题列表来进行一些练习。

即使我尝试编写像第一个问题一样微不足道的东西(在 Go 中这将是一条语句,获取切片的最后一个元素),我将如何将其编写为一个接受任何类型切片的函数和(使用我上面引用的那条语句)返回该切片的最后一个元素?

我认为即使该语言没有参数多态性,也必须有一些惯用的“Go”方式来做到这一点,以便 Go 常客声称他们不会错过参数多态性。否则,如果示例比列表的最后一个元素更复杂,您将需要一个函数来执行每种类型的任务。

我错过了什么?

4

4 回答 4

13

您引用了“99 lisp 问题”,但 Lisp 根本没有参数多态性或静态类型。

许多静态类型语言,如 Objective-C 和泛型之前的 Java,没有参数多态性。解决方案是只使用可以接受所有值的类型,在 Go 中是interface{},并在需要从中获取某些特定类型时进行强制转换。

对于您的具体问题,如何采取“任何类型的切片”;不幸的是,没有专门包含切片的接口,因为切片没有任何方法;所以你会被困在使用interface{}. 由于您有一个未知的切片类型,您需要使用反射(reflect包)来执行所有切片操作,包括获取长度和容量、追加和访问特定索引处的元素。

另一种选择是,不要使用“任何类型的切片”,而是使用“界面切片{}”,即[]interface{}在所有代码中,然后您可以在其上使用普通切片运算符,并且可以放入任何元素,但是当你把它们拿出来时施放。

于 2011-10-18T01:38:42.107 回答
8

如何返回切片的最后一个元素的 Go 方法是简单地将其内联写为表达式。例如:

var a []int
...
last := a[len(a)-1]

将简单表达式封装a[len(a)-1]到泛型函数中是不必要的复杂化。

与 Lisp 不同,Go 不是纯粹的函数式语言。根据 99 个 Lisp 问题的列表评估 Go 可能具有欺骗性。Go 是一种“系统编程语言”——列表操作、元编程、符号 AI 或其他适合 Lisp 的任务并不是 Go 的强项。

我将 Go 视为具有垃圾收集和并发性的改进C。Go 不是来与 Lisp 竞争的。

于 2011-10-18T16:32:33.877 回答
1

这听起来很像当我发现我用其他编程语言(如 C、fpc 或 delphi)为不同类型的不同数组多次编写相同的代码时。我为一种可能永远不会实现的语言发明了参数多态性,使用预处理器技巧并将其称为“包含文件参数多态性”作为概念证明,您实际上可以在不需要 OOP 或任何复杂的程序语言中实现参数多态性泛型系统。但是,使用预处理器是一种滥用形式,它只是为了用 FPC 来证明这个概念。

由于 Golang 不使用预处理器,因此您必须使用接口或指针并将类型作为参数发送。但即使使用指针仍然意味着您必须编写大量代码来转换它并使其全部工作。接口比指针好,因为指针不太安全。

像这样的解决方案:

last := a[len(a)-1]

容易出现错误,因为有人可能会忘记负 1。有些语言有一些更好的东西:

// return last element, the "high" of a
last := a[high(a)]
// return first element, the "low" of a
first := a[low(a)]

上面的代码在 Go AFAIK 中不起作用(还没有研究 go 是否有类似的东西),这正是其他一些语言所具有的(fpc)可能是 Go 考虑的东西。

这种处理事物的低和高方式绝对确保选择最后一个和第一个元素,而使用“减一”容易产生基本的数学错误。有人可能会忘记减一...因为他们对基于 1 的数组与基于零的数组感到困惑。即使该语言没有基于 1 的数组之类的东西,由于人类有时会以基于 1 的方式思考(我们的手指从 1 开始,而不是 0),仍然可能会出错。一些聪明的程序员会争辩说,不,我们的手指从零开始,而不是从一开始。你的拇指为零。好吧,很好..但是..对于世界上的大多数人来说......;-) 我们最终在现实世界与计算机世界中整天从 1 到 0 来回切换我们的大脑,这导致了许多软件中的错误。

但是有些人会争辩说“低”和“高”只是语法糖,在最小语言中不是必需的。必须决定额外的安全是否值得,在许多情况下是值得的。我不确定 LOW() 和 HIGH() 给编译器增加了多少复杂性,以及它如何影响性能。我不是 100% 确定……我认为编译器可以很聪明地优化高低,但我不确定。

于 2015-09-15T20:37:33.087 回答
0

只是回答如何获取数组的最后一个(也是第一个)元素的问题,这是 Go 中的正确方法:

last := a[:1] first := a[1:]

但这与参数多态性无关,即类型推断并在编译时计算。

我正在尝试编写一个二叉树库,但我仍在努力以最有效、可读性和高性能的方式来抽象数据类型,具体来说,我已经编写了存储、光标和索引映射系统,并且walk 函数,但我希望能够切换出实际存储在节点中的数据类型。我在这个过程中学到了很多关于作曲和嵌入的知识,但这并没有让我完全开心。

我确实知道一点函数式编程的原理,而 Go 恰好将函数视为第一类,所以理论上可能有一个函数式解决方案来解决参数多态性问题。我正在解决这个问题,因为基本上我喜欢函数式范式,但无论如何我讨厌递归(我更喜欢迭代,对我来说更容易可视化 100 倍)。

于 2018-04-22T10:38:44.700 回答