Golang:使用另一个结构体进行类型赋值。

huangapple go评论83阅读模式
英文:

Golang: Type assign with another struct

问题

这是一个示例代码,它定义了几个结构体和方法。你想知道为什么可以从嵌入的Circle中调用Something方法,但不能从Form类型中的Rectangle调用SomethingElse方法。另外,你还想知道在声明一个类型时,像在Form中声明的那样,会有什么好处。

首先,让我们来解释一下为什么可以从嵌入的Circle中调用Something方法。在Go语言中,嵌入类型是一种组合机制,它允许一个结构体类型嵌入到另一个结构体类型中,从而继承嵌入类型的字段和方法。在这个例子中,Rectangle结构体嵌入了Circle结构体,因此Rectangle类型继承了Circle类型的字段和方法。所以你可以通过c.Circle.Something()来调用Something方法。

接下来,我们来解释一下为什么不能从Form类型中的Rectangle调用SomethingElse方法。在这个例子中,Form类型是通过将Rectangle类型声明为Form类型来创建的。尽管Form类型继承了Rectangle类型的字段和方法,但是由于方法集的限制,你不能直接通过c.SomethingElse()来调用SomethingElse方法。方法集是指类型上可直接调用的方法的集合。在这种情况下,Form类型的方法集只包含从Rectangle类型继承的方法,而不包含从Circle类型继承的方法。因此,你需要通过c.Rectangle.SomethingElse()来调用SomethingElse方法。

最后,关于在声明一个类型时像在Form中声明的那样的好处。通过声明一个类型为另一个类型,你可以为已有的类型创建一个新的类型别名。这样做的好处之一是可以为已有类型添加额外的方法,而无需修改原始类型的定义。在这个例子中,通过将Rectangle声明为Form类型,你可以为Rectangle类型添加新的方法,而不会影响到Rectangle类型本身。这种方式可以提高代码的可读性和可维护性。

希望这些解释对你有帮助!如果还有其他问题,请随时提问。

英文:

So I have this example here:
Go Playground

package main

import (
	"fmt"
)

type Circle struct{}

func (c Circle) Something() {
	fmt.Println("something")
}

type Rectangle struct {
	Circle
}

func (a Rectangle) SomethingElse() {
	fmt.Println("SomethingElse")
}

type Form Rectangle

func main() {
	c := Form{}
	c.Circle.Something()
    c.SomethingElse()
}

I don't understand why I can call Something from the embedded Circle, but cannot call Somethingelse from the Rectangle within the Form type. Also I don't understand what benefit I get when I declare a type of some other type, like here in Form.

答案1

得分: 20

这段代码的翻译如下:

这段代码定义了一个名为Form的新类型,其底层类型是Rectangle

这意味着Rectangle结构体的字段也会被定义在Form类型中。

但是方法是绑定到特定类型的。当你创建一个新类型(Form)时,这个新类型不会继承其底层类型的任何方法,所以你不能调用c.SomethingElse(),因为SomethingElse()Rectangle类型的方法。

c.Circle.Something()是可以工作的,因为c.Circle是类型为Circle的字段,而Something()Circle类型的方法。

如果你想调用Rectangle.SomethingElse()方法,那就需要一个Rectangle类型的值(接收者类型是Rectangle)。由于Form的底层类型是Rectangle,你可以通过简单的类型转换从Form类型的值中获取一个Rectangle类型的值:

Rectangle(c).SomethingElse() // 这样可以工作

创建一个新类型的好处是你可以为其创建/添加自己的方法。一个常见的例子是实现sort.Interface接口。假设你有一个切片,比如[]Rectangle,或者一个你无法控制的其他类型的切片(因为它是另一个包的一部分——类型的方法只能在同一个包中定义)。如果你想对这个切片进行排序,你可以创建一个新类型,并为其定义方法,这些方法实现了sort.Interface,例如:

type SortRectangle []Rectangle

func (s SortRectangle) Len() int           { return len(s) }
func (s SortRectangle) Less(i, j int) bool { return s[i] <some-logic> s[j] }
func (s SortRectangle) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

sort.Sort()函数能够对任何实现了sort.Interface的值进行排序。[]Rectangle类型并没有实现该接口,但是我们刚刚创建了一个新类型SortRectangle来实现它。如果我们有一个[]Rectangle类型的值,我们可以将其转换为SortRectangle类型,因为前者是后者的底层类型,通过进行转换,我们就得到了一个SortRectangle类型的值,可以传递给sort.Sort()函数进行排序:

rs := []Rectangle{}
// 对rs进行排序:
sort.Sort(SortRectangle(rs))

需要注意的是,上述的SortRectangle(rs)转换只改变了运行时的类型信息,它并不改变rs的内存表示,所以这是完全安全和高效的。

如果你希望新类型具有"旧"类型的方法,可以使用嵌入。请参考Ainar-G的回答。实际上,你已经通过将Circle嵌入Rectangle来实现了这一点:类型Rectangle具有一个Something()方法,因为Something()Circle的方法:

Rectangle{}.Something()  // 输出 "something"
英文:

This:

type Form Rectangle

Creates a new type named Form, having Rectangle as its underlying type.

This means that the fields of Rectangle (which is a struct) will be defined for Form as well.

But methods are bound to a specific type. When you create a new type (Form), that new type will not have any of the methods of its underlying type, so you can't call c.SomethingElse() as SomethingElse() is a method of the Rectangle type.

c.Circle.Something() works, because c.Circle is a field of type Circle, and Something() is a method of the Circle type.

If you want to call the Rectangle.SomethingElse() method, that requires a value of type Rectangle (the receiver type is Rectangle). Since underlying type of Form is Rectangle, you can simply obtain a value of type Rectangle from a value of type Form using a simple type conversion:

Rectangle(c).SomethingElse() // This works

The benefit of creating a new type is that so you can create / add your own methods for it. A common example is implementing the sort.Interface interface. Let's say you have a slice of something, e.g. []Rectangle, or a slice of some type which you have no control over (beause it's part of another package – and methods for a type can only be defined in the same package). If you want to sort this slice, you create a new type for which you can define methods, the methods of sort.Interface, e.g.:

type SortRectangle []Rectangle

func (s SortRectangle) Len() int           { return len(s) }
func (s SortRectangle) Less(i, j int) bool { return s[i] <some-logic> s[j] }
func (s SortRectangle) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

The sort.Sort() function is able to sort any values that implement sort.Interface. The []Rectangle does not, but we just created a new type SortRectangle which does. And if we have a value of type []Rectangle, we can convert it to SortRectangle because the former is the underlying type of the latter, and by doing a conversion, we have a value of type SortRectangle which can be passed to sort.Sort(), in order to have it sorted:

rs := []Rectangle{}
// Sort rs:
sort.Sort(SortRectangle(rs))

Note that a conversion like the above SortRectangle(rs) only changes the runtime type information, it does not change the memory representation of rs, so it's pefectly safe and efficient.

If you want the new type to have the methods of the "old" type, then use embedding. See Ainar-G's answer. In fact, you already did this by embedding Circle in Rectangle: the type Rectangle has a method Something(), because Something() is a method of Circle:

Rectangle{}.Something()  // Prints "something"

答案2

得分: 7

在Go语言中有一个简单的规则。如果你想要类型的方法,可以这样写:

type A struct { B }

如果你不想要类型的方法,可以这样写:

type A B

为什么我们需要第二种形式呢?接口,例如。有时候我们不想让一个值满足一个接口,就像这里所示。其他时候,你只需要类型而不需要它的方法。

Go语言提供了一种方式,可以获得相同的类型,但是没有方法集合。

英文:

A simple rule in Go. If you want the type's methods, do

type A struct { B }

and if you don't want the type's methods, do

type A B

Why do we need the second form? Interfaces, for example. Sometimes we don't want a value to satisfy an interface, like here. Other times you just need the types and not its methods.

Go gives you the possibility to get the type that is the same, but with an empty method set.

答案3

得分: 1

定义type Form Rectangle 的唯一目的是定义一个具有不同方法的_新类型_。在你的例子中:没有方法。c 是一个 Form,没有方法,它的唯一存在理由是_没有_ SomethingElse() 方法。

但是,一个 Form 仍然嵌入了一个可通过 c.Circle 访问的 Circle,并且它是一个 Circle,所以显然具有 Something() 方法。

英文:

The whole (and only) reason to do type Form Rectangle is to define a new type with different methods. In your example: No methods. c is a Form and has no methods, it's only raison d'être is not having a SomethingElse() method.

But a Form still embeds a Circle which is accessible as c.Circle and which is a Circle so it obviousely has the method Something().

huangapple
  • 本文由 发表于 2016年10月26日 03:29:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/40248156.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定