我是Go的新人,但我读过Go常规者不会错过参数多态。每当我尝试学习一门新语言时,我都会使用the L99 list of problems来练习。
即使我尝试写一些像第一个问题一样微不足道的东西(在Go中是一个单一的语句,取一个切片的最后一个元素),我怎么把它写成一个带有任何类型切片的函数和(使用我上面引用的那个单一语句)返回该切片的最后一个元素?
我认为即使语言没有参数多态,也必须有一些惯用的“Go”方式,以便Go常规声称他们不会错过参数多态。否则,如果示例比例如列表的最后一个元素更复杂,则需要一个函数来为每个类型执行任务。
我错过了什么?
答案 0 :(得分:13)
你引用了“99个lisp问题”,但Lisp根本没有参数多态或静态类型。
许多静态类型的语言,如Objective-C和Java之前的泛型,没有参数多态。解决方案是只使用一个可以接受所有值的类型,在Go中为interface{}
,并在需要从中获取某些特定类型时进行转换。
针对您的具体问题,如何采取“任何类型的切片”;遗憾的是,没有包含特定切片的接口,因为切片没有任何方法;因此,您将无法使用interface{}
。由于您具有未知的切片类型,因此需要使用反射(reflect
包)来执行所有切片操作,包括获取长度和容量,附加以及访问特定索引处的元素。
另一个替代方案是,不要使用“任何类型的切片”,只需在所有代码中使用“切片接口{}”即[]interface{}
,然后就可以在其上使用普通切片运算符,并且你可以把任何元素放进去,但是当你把它们拿出来时就会施放。
答案 1 :(得分: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竞争。
答案 2 :(得分:1)
这听起来很像当我发现我在其他编程语言(如C,fpc或delphi)中为不同类型的不同数组多次编写相同的代码时。我发明了一种可能永远不会实现它的语言的参数多态性,使用预处理器技巧并称之为“#34;包含文件参数多态性"作为概念证明,您实际上可以将参数多态性实现为过程语言而无需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"和"高"只是语法糖,在最小的语言中是不必要的。必须确定额外的安全性是否值得,在许多情况下它是可以的。 LOW()和HIGH()增加了多少复杂性给编译器我不确定,以及它如何影响性能..我不是百分百肯定...我认为编译器可以很聪明地优化高低,但我不确定。
答案 3 :(得分:0)
回答如何获取数组的最后一个(和第一个)元素的问题,这是Go中的正确方法:
last := a[:1]
first := a[1:]
但这与参数多态无关,即类型推断,并在编译时计算。
我正在尝试编写二叉树库,我仍在努力用最有效,最易读和最高效的方式来抽象数据类型,具体来说,我有商店,光标和索引映射系统写入和遍历函数,但我希望能够切换实际存储在节点中的数据类型。我在这个过程中学到了很多关于构图和嵌入的知识,但这并没有让我完全开心。
我确实知道一些函数式编程的原理,而Go恰好将函数视为第一类,因此理论上可能存在参数多态性问题的功能性解决方案。我正在弄清楚因为基本上我喜欢功能范例,但我还是讨厌递归(我更喜欢迭代,100x更容易让我想象)。