无法将结构转换为具有相同基础字段的不同类型
Cannot convert struct to different type with same underlying fields
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
}
根据这个 this question 及其答案,我觉得我应该能够做到以下几点:
req := &Req{}
req = TestReq(req)
但我在 VsCode 中收到此错误:
cannot convert req (variable of type *Req) to TestReq compiler(InvalidConversion)
这两个结构体不是有相同的底层字段吗?如果可以,为什么第一个不能转换为第二个?
Don't these two structs have the same underlying fields?
不,他们没有。 Req
有多个字段,TestReq
有一个类型为 Req
的字段,因此它们不会 convertible 相互。嵌入不会将嵌入类型的字段“复制”到嵌入器类型。嵌入添加一个字段,可以通过其类型的非限定类型名称引用。
嵌入的使用不是自动“复制”字段,而是让它们“提升”,同时提升嵌入类型的方法。
如果你有一个 TestReq
类型的值,你可以使用非限定类型名称 Req
来引用嵌入字段,所以你可以这样做:
var tr TestReq
var r Req
r = tr.Req // Valid
tr.Req = r // This is also valid
上述操作(语句)是assignments,因此,它们复制了整个Req
结构值。如果你想避免这种情况,你可以嵌入一个指针,例如:
type TestReq struct {
*Req
}
然后下面的赋值只会复制一个指针值:
var tr = &TestReq{Req: &Req{}}
var r *Req
r = tr.Req // Valid
tr.Req = r // This is also valid
(注意:tr
本身在这里可能是也可能不是指针,没关系。)
根据icza的建议,使用类型名req给embedded赋值field.Here是一个简单的代码,为简单起见,我将redis、logrus、context和http类型转换为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)
}
输出:
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}}
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
}
根据这个 this question 及其答案,我觉得我应该能够做到以下几点:
req := &Req{}
req = TestReq(req)
但我在 VsCode 中收到此错误:
cannot convert req (variable of type *Req) to TestReq compiler(InvalidConversion)
这两个结构体不是有相同的底层字段吗?如果可以,为什么第一个不能转换为第二个?
Don't these two structs have the same underlying fields?
不,他们没有。 Req
有多个字段,TestReq
有一个类型为 Req
的字段,因此它们不会 convertible 相互。嵌入不会将嵌入类型的字段“复制”到嵌入器类型。嵌入添加一个字段,可以通过其类型的非限定类型名称引用。
嵌入的使用不是自动“复制”字段,而是让它们“提升”,同时提升嵌入类型的方法。
如果你有一个 TestReq
类型的值,你可以使用非限定类型名称 Req
来引用嵌入字段,所以你可以这样做:
var tr TestReq
var r Req
r = tr.Req // Valid
tr.Req = r // This is also valid
上述操作(语句)是assignments,因此,它们复制了整个Req
结构值。如果你想避免这种情况,你可以嵌入一个指针,例如:
type TestReq struct {
*Req
}
然后下面的赋值只会复制一个指针值:
var tr = &TestReq{Req: &Req{}}
var r *Req
r = tr.Req // Valid
tr.Req = r // This is also valid
(注意:tr
本身在这里可能是也可能不是指针,没关系。)
根据icza的建议,使用类型名req给embedded赋值field.Here是一个简单的代码,为简单起见,我将redis、logrus、context和http类型转换为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)
}
输出:
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}}