英文:
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()
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论