英文:
Go polymorphism in function parameters
问题
我发现了几个标题相似的问题,但在它们中找不到我问题的答案:
我有以下简单的场景:
类型:
type intMappedSortable interface {
getIntMapping() int
}
type Rectangle struct {
length, width int
}
func (r Rectangle) getIntMapping() int {
return r.Area();
}
func (Rectangle r) getIntMapping() int {
return r.length * r.width;
}
主函数:
func main() {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
var values []int
values = make([]int, 0)
for i := 0; i < 10; i++ {
values = append(values, r.Intn(20))
}
var rects []Rectangle;
rects = make([]intMappedSortable, len(values));
for i,v:= range values {
r := Rectangle{v,v};
rects[i] = r;
}
for i,v:= range rects {
fmt.Println(v.Area());
}
rectsRet := make(chan intMappedSortable, len(rects));
sort(rects, rectsRet);
}
doWork函数:
func sort(values []intMappedSortable, out chan intMappedSortable) {...}
我如何将矩形传递给排序函数,然后在主函数中处理排序后的矩形?
我尝试过:
var rects []*Rectangle;
rects = make([]*Rectangle, len(values));
作为我从C语言时代养成的习惯,我不想复制矩形,只想复制地址,这样我就可以直接在原始切片中进行排序,避免对整个数据进行两次复制过程。
在这个失败后,我尝试了:
var rects []intMappedSortable;
rects = make([]*Rectangle, len(values));
我了解到Go通过持有指向未公开的原始数据的指针来处理"多态性",所以我将*Rectangle更改为Rectangle,但两者都给我编译器错误,即Rectangle不是[]intMappedSortable。
显然有效的方法是:
var rects []intMappedSortable;
rects = make([]intMappedSortable, len(values));
for i,v:= range values {
r := Rectangle{v,v};
rects[i] = r;
}
但是这些矩形是复制的还是只是接口的内存表示与它们的引用复制了?此外,现在无法访问矩形的长度和宽度,因为切片不再明确是矩形类型。
那么,我应该如何实现这个场景呢?
我想创建一个包含任何实现mapToInt()方法的结构的切片,对切片进行排序,然后在排序后继续使用具体类型。
编辑/后续问题:
我知道这不是好的编程风格,但我正在进行实验:
我是否可以以某种方式使用类型断言和动态类型,例如:
func maptest(values []intMappedSortable, out interface{}) {
oType := reflect.TypeOf(out);
fmt.Println(oType); // --> chan main.intMappedSortable
test := values[0].(oType) //我知道这不起作用,甚至在思想上是错误的,因为oType保存的是"chan intMappedSortable",但只是为了理论的完整性
}
我该如何做到这一点,或者这不可能吗?我不是指它是否"应该这样做",我知道不应该。但是它可能吗?^^
英文:
i found several questions with similar titles, but cannot find the answer to my question in them:
I have the following simple scenario:
types:
type intMappedSortable interface {
getIntMapping() int
}
type Rectangle struct {
length, width int
}
func (r Rectangle) getIntMapping() int {
return r.Area();
}
func (Rectangle r) getIntMapping() int {
return r.length * r.width;
}
main:
func main() {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
var values []int
values = make([]int, 0)
for i := 0; i < 10; i++ {
values = append(values, r.Intn(20))
}
var rects []Rectangle;
rects = make([]intMappedSortable, len(values));
for i,v:= range values {
r := Rectangle{v,v};
rects[i] = r;
}
for i,v:= range rects {
fmt.Println(v.Area());
}
rectsRet := make(chan intMappedSortable, len(rects));
sort(rects, rectsRet);
}
doWork:
func sort(values []intMappedSortable, out chan intMappedSortable) {...}
How do i manage to pass the Rectangles to the sorting function and then work with the sorted rectangles in main after it?
I tried:
var rects []*Rectangle;
rects = make([]*Rectangle, len(values));
as a habit from my C days, i don't want to copy the rectangles, just the addresses, so i can sort directly in the original slice, preventing 2 copy procedures for the whole data.
After this failed i tried:
var rects []intMappedSortable;
rects = make([]*Rectangle, len(values));
i learned that Go handles "polymorphism" by holding a pointer to the original data which is not exposed, so i changed *Rectangle to Rectangle, both gave me the compilererror that Rectangle is not []intMappedSortable
What obviously works is:
var rects []intMappedSortable;
rects = make([]intMappedSortable, len(values));
for i,v:= range values {
r := Rectangle{v,v};
rects[i] = r;
}
But are are these rectangles now copied or is just the memoryrepresentation of the interface with their reference copied? Additionally there now is no way to access length and width of the rectangles as the slice is not explicitly of type rectangle anymore.
So, how would i implement this scenario?
I want to create a slice of ANY structure, that implements the mapToInt(), sort the slice and then keep working with the concrete type after it
EDIT/FOLLOWUP:
I know its not good style, but i'm, experimenting:
can i somehow use type assertion with a dynamic type like:
func maptest(values []intMappedSortable, out interface{}) {
oType := reflect.TypeOf(out);
fmt.Println(oType); // --> chan main.intMappedSortable
test := values[0].(oType) //i know this is not working AND wrong even in thought because oType holds "chan intMappedSortable", but just for theory's sake
}
how could i do this, or is this not possible. I do not mean wether it is "meant to be done", i know it is not. But is it possible?^^
答案1
得分: 1
但是这些矩形是被复制了,还是只是它们的接口的内存表示与它们的引用被复制了?
后者,参见“在golang中interface{}
的含义是什么?”
一个接口值由两个数据字组成:
- 一个字用于指向该值底层类型的方法表,
- 另一个字用于指向该值所持有的实际数据。
我想创建一个包含任何结构体的切片,对切片进行mapToInt()
操作,然后对切片进行排序,并在此之后继续使用具体类型。
这是不可能的,因为Go语言中没有泛型。
参见“Go语言中的泛型是什么?”
这就是为什么有像“gen”这样的项目:
在开发时,使用命令行为您的类型生成代码。
gen
不是一个导入包;生成的源代码成为您的项目的一部分,不依赖于外部库。
英文:
> But are are these rectangles now copied or is just the memory representation of the interface with their reference copied?
The latter, see "what is the meaning of interface{}
in golang?"
> An interface value is constructed of two words of data:
> - one word is used to point to a method table for the value’s underlying type,
- and the other word is used to point to the actual data being held by that value.
> I want to create a slice of ANY structure, that implements the mapToInt(), sort the slice and then keep working with the concrete type after it
That isn't possible, as there is no genericity in Go.
See "What would generics in Go be?"
That is why you have projects like "gen":
> generates code for your types, at development time, using the command line.
gen
is not an import; the generated source becomes part of your project and takes no external dependencies.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论