英文:
Cannot convert struct to different type with same underlying fields
问题
根据这个问题和它的答案,我觉得我应该能够做以下操作:
req := &Req{}
req = TestReq(req)
但是在 VsCode 中我得到了这个错误:
无法将 req(类型为 *Req 的变量)转换为 TestReq 编译器(InvalidConversion)
这两个结构体不是有相同的底层字段吗?如果是这样,为什么第一个不能转换为第二个?
英文:
type Req struct {
apiVersion string
path string
resourceEndpoint string
accessKey string
log *logrus.Entry
incomingReq interface{}
httpClient lib.HTTPClient
redisClient redis.Cmdable
ctx context.Context
}
type TestReq struct {
Req
}
According to this this question and its answers, I feel like I should be able to do the following:
req := &Req{}
req = TestReq(req)
But I get this error in VsCode:
> cannot convert req (variable of type *Req) to TestReq compiler(InvalidConversion)
Don't these two structs have the same underlying fields? If so, why can't the first be converted into the second?
答案1
得分: 7
这两个结构体的底层字段不相同。Req
有几个字段,TestReq
只有一个类型为Req
的字段,因此它们不能相互转换。嵌入并不会将嵌入类型的字段“复制”到嵌入者类型中。嵌入会添加一个单一的字段,可以通过其类型的未限定类型名称来引用。
嵌入的作用不是自动“复制”字段,而是将它们“提升”,同时也提升了嵌入类型的方法。
如果你有一个类型为TestReq
的值,你可以使用未限定类型名称Req
来引用嵌入字段,所以你可以这样做:
var tr TestReq
var r Req
r = tr.Req // 有效
tr.Req = r // 也是有效的
上述操作(语句)是赋值操作,因此它们会复制整个Req
结构体的值。如果你想避免这种情况,可以嵌入一个指针,例如:
type TestReq struct {
*Req
}
然后以下赋值操作只会复制一个指针值:
```go
var tr = &TestReq{Req: &Req{}}
var r *Req
r = tr.Req // 有效
tr.Req = r // 也是有效的
(注意:`tr`本身可以是指针,也可以不是指针,这并不重要。)
<details>
<summary>英文:</summary>
> Don't these two structs have the same underlying fields?
No, they don't. `Req` has several fields, `TestReq` has a single field of type `Req` so they are not [convertible](https://golang.org/ref/spec#Conversions) into each other. Embedding does not "copy" the fields of the embedded type to the embedder type. Embedding adds a single field which can be referred to by the unqualified type name of its type.
<sup>The use of embedding is not to automatically "copy" the fiels, but rather to have them "promoted", also promoting the methods of the embedded type.</sup>
If you have a value of type `TestReq`, you may use the unqualified type name `Req` to refer to the embedded field, so you may do something like this:
var tr TestReq
var r Req
r = tr.Req // Valid
tr.Req = r // This is also valid
The above operations (statements) are [assignments](https://golang.org/ref/spec#Assignments) and as such, they copy the whole `Req` struct value. If you want to avoid that, you may embed a pointer, for example:
type TestReq struct {
*Req
}
And then the following assignments will only copy a pointer value:
var tr = &TestReq{Req: &Req{}}
var r *Req
r = tr.Req // Valid
tr.Req = r // This is also valid
(Note: `tr` itself may or may not be a pointer here, it doesn't matter.)
</details>
# 答案2
**得分**: 1
根据icza的建议,使用类型名称req为嵌入字段赋值。以下是相同功能的简单代码,为了简化,我将redis、logrus、context和http类型转换为interface{}。
```go
package main
import (
"fmt"
)
type Req struct {
apiVersion string
path string
resourceEndpoint string
accessKey string
log interface{}
incomingReq interface{}
httpClient interface{}
redisClient interface{}
ctx interface{}
}
type TestReq struct {
Req
}
func main() {
req1 := Req{"api01", "c:/doc/folder", "endkey", "ackey", "logs", [2]float64{2.0, 7.88}, "http", "redis", "ctx"}
fmt.Println("ReqObject", req1)
var testReq TestReq
testReq.Req = req1
fmt.Println("TestReqObject", testReq)
}
输出结果:
ReqObject {api01 c:/doc/folder endkey ackey logs [2 7.88] http redis ctx}
TestReqObject {{api01 c:/doc/folder endkey ackey logs [2 7.88] http redis ctx}}
英文:
Based on the suggestion icza, using the type name req to assign value to embedded field.Here is a simple code for the same , for simplicity I converted redis,logrus,context and http types as interface{}
package main
import (
"fmt"
)
type Req struct {
apiVersion string
path string
resourceEndpoint string
accessKey string
log interface{}
incomingReq interface{}
httpClient interface{}
redisClient interface{}
ctx interface{}
}
type TestReq struct {
Req
}
func main() {
req1 := Req{"api01", "c:/doc/folder", "endkey", "ackey", "logs", [2]float64{2.0, 7.88}, "http", "redis", "ctx"}
fmt.Println("ReqObject",req1)
var testReq TestReq
testReq.Req = req1
fmt.Println("TestReqObject",testReq)
}
Output:
ReqObject {api01 c:/doc/folder endkey ackey logs [2 7.88] http redis ctx}
TestReqObject {{api01 c:/doc/folder endkey ackey logs [2 7.88] http redis ctx}}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论