英文:
Any type and implementing generic list in go programming language
问题
我正在尝试一点点Go编程语言。
我对Go的简洁性感到兴奋,但在使用它时遇到了一些问题。
- 我知道Go不支持泛型和继承。<b>有没有办法实现泛型列表?</b>
我考虑使用:
type Any interface { }
但是如何检查值是否为NULL呢?<br />
我正在寻找一些等效于C的实现
<!-- language: lang-cpp -->
struct List {
List* tail;
void* head;
}
或者使用代数数据类型:
<!-- language: lang-haskell -->
data List a = Nil | Cons a (List a)
<br/>
2. 更高级的要求是<b>创建一个包含特定类型字段的对象容器?</b><br />
例如,在<em>Scala编程语言</em>中,我可以输入:
<!-- language: lang-scala -->
val List[Animal { type SuitableFood = Grass} ]
以获得一个具有成员类型SuitableFood
为Grass
的Animal
列表
英文:
I'm trying a little of go programming language.
I'm a excited about the simplicity of the Go, but after playing with it I met some troubles.
1 . I know that Go doesn't support generics and inheritance. <b>Is there any way to implement generic list?</b>
I thinking about using:
type Any interface { }
but how can I check if the value is NULL.<br />
I'm looking for some equivalent implementation to C
<!-- language: lang-cpp -->
struct List {
List* tail;
void* head;
}
Or using algebraic datatype:
<!-- language: lang-haskell -->
data List a = Nil | Cons a (List a)
<br/>
2 . More advanced requirement would be to <b>make some container for objects with a field of a particular type?</b><br />
For example in <em>Scala programming language</em> I can type:
<!-- language: lang-scala -->
val List[Animal { type SuitableFood = Grass} ]
to get a List
of Animals
, which have a member type SuitableFood
which is Grass
答案1
得分: 3
你可以拥有一个类型为interface{}
的元素列表。你可以放入任何元素,当你取出时,你必须将其强制转换回你想要的类型。这就像你在C示例中所做的void *
,以及在泛型之前的Java列表和Objective-C中的列表,它们都没有泛型。Go库中的所有容器都是这样做的。
没有泛型,元素类型没有编译时检查。
如果你真的想要,你可以通过使用反射来获取元素类型并将其与预期类型进行检查,实现运行时检查元素类型。然而,这可能是过度设计。
英文:
You can have a list of elements of type interface{}
. You can put any elements in, and when you get it out, you have to cast back to the type you want. This is like what you're doing void *
in your C example; and also like lists in Java before Generics, and in Objective-C, which doesn't have generics. All the containers in the Go library do this.
Without generics, there is no compile-time checking of the element types.
If you really wanted, you could implement run-time checks for element type, by using reflection to get the element types and checking them against the expected type. However, this is probably overkill.
答案2
得分: 3
Go 1.18已经支持泛型。我预计标准库最终会添加泛型容器,类似于当前的container/list
包,这样你就不必重复造轮子了。
不过,作为一种思考练习,你可以复制标准的list.List
并自己添加类型参数:
type Element[T any] struct {
next, prev *Element[T]
list *List[T]
Value T
}
type List[T any] struct {
root Element[T]
len int
}
// 简化的构造函数
func New[T any]() *List[T] {
l := new(List[T])
l.root.next = &l.root
l.root.prev = &l.root
l.len = 0
return l
}
如你所见,Element
结构体可以有一个类型为Element
的字段,但类型参数必须是相同的,并且按照相同的顺序(来源)。
你可以通过将约束any
替换为指定所需方法的接口约束来为具有特定类型字段的对象创建容器,例如:
type Animal interface {
SuitableFood() string
}
type Element[T Animal] struct {
// ...
}
这将约束类型参数为实现了Animal
接口的类型。
你不能将类型参数约束为具有特定字段1。如果你必须强制T
具有特定的值,你可以将更具体的方法添加到接口约束中,例如SuitableFoodGrass()
,但这是一个泄漏的抽象。接口模型化行为,你应该坚持这个原则。
1:从技术上讲,你可以使用带有结构体的类型约束,但这并不是非常有用。
英文:
> I know that Go doesn't support generics [...]
It does as of Go 1.18. I expect the standard library to eventually add generic containers along the current container/list
package so you don't have to reinvent the wheel.
Anyway as a thought exercise you could copy the standard list.List
and add type parameters yourself:
type Element[T any] struct {
next, prev *Element[T]
list *List[T]
Value T
}
type List[T any] struct {
root Element[T]
len int
}
// simplified constructor
func New[T any]() *List[T] {
l := new(List[T])
l.root.next = &l.root
l.root.prev = &l.root
l.len = 0
return l
}
As you can see Element
struct can have a field of type Element
, but the type params must be the same ones and in the same order (source).
> make some container for objects with a field of a particular type?
You can do this by replacing the constraint any
with an interface constraint that specified the method you want, for example:
type Animal interface {
SuitableFood() string
}
type Element[T Animal] struct {
// ...
}
and this constrains the type parameter to those that implement the Animal
interface.
<hr>
What you can not do is constrain the type param to have a particular field<sup>1</sup>. If you must force T
to have specific values, you could instead add a more specific method to the interface constraint, e.g. SuitableFoodGrass()
but that's a leaky abstraction. Interfaces model behavior, and you should stick to that principle.
<hr>
<sup>1: Technically you can, using a type constraint with a struct, but it wouldn't be very useful</sup>.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论