Go 的范型怎么把 Response[指定类型] 转换为 Response[any]

讨论 未结 25 31
jorneyr
jorneyr 会员 2023年1月28日 02:56 发表
<p>问题: Go 的范型怎么把 Response[指定类型] 转换为 Response[any].</p> <p>下面的示例代码在 [3] 部分进行类型转换的时候报错 cannot use rsp2 (variable of type Response[map[string]string]) as Response[any] value in assignment 。</p> <pre><code class="language-go">package main import ( "encoding/json" "fmt" ) type Response[T any] struct { Code int `json:"code"` // 业务逻辑相关的 code ,不是 HTTP Status Code Success bool `json:"success"` // 业务逻辑处理成功时为 true ,错误时为 false Msg string `json:"msg"` // 请求的描述 Data T `json:"data,omitempty"` // 请求的 payload } func main() { } func foo[T any]() Response[any] { // [1] 创建范型对象 rsp1 := Response[map[string]string]{ Code: 200, Success: true, Data: map[string]string{"1": "one", "2": "two"}, } // [2] 范型序列化 b, _ := json.Marshal(rsp1) fmt.Println(string(b)) // [3] 范型反序列化 var rsp2 Response[map[string]string] json.Unmarshal(b, &amp;rsp2) fmt.Printf("%+v\n", rsp2) // [4] 范型向上类型转换 // 相当于 Java 的范型用 ? 来接收任意类型的范型如 // List&lt;String&gt; list1 = new LinkedList&lt;&gt;(); // List&lt;?&gt; list2 = list1; rsp3 := Response[any]{} rsp3 = rsp2 // 错误: cannot use rsp2 (variable of type Response[map[string]string]) as Response[any] value in assignment return rsp3 } </code></pre>
收藏(0)  分享
相关标签: 灌水交流
注意:本文归作者所有,未经作者允许,不得转载
25个回复
  • nobot
    2023年1月28日 03:26
    返回值需要明确知道类型,不然编译器,无法特例化对应类型的函数
    0 0
  • jorneyr
    2023年1月28日 03:26
    还不到返回值类型的地方,rsp3 = rsp2 赋值的时候就报错了。
    0 0
  • hahadaxigua834
    2023年1月28日 03:26
    func (x *Response[T]) ToAny() Response[any] { return Response[any]{ Code: x.Code, Success: x.Success, Msg: x.Msg, Data: x.Data, } }
    0 0
  • jorneyr
    2023年1月28日 03:26
    我想定义一个函数,接收任意类型的 Response[any],然后处理后返回给客户端,所以这个函数的目录就是接收任意类型的 Response ,也就是上面用 rsp3 = rsp2 进行演示。 返回 Response[T] 满足不了需求。
    0 0
  • rrfeng
    2023年1月28日 03:26
    你都上泛型了为啥要 any……是不是跑偏了
    0 0
  • kaf
    2023年1月28日 03:26
    编译错误说明了 Response[map[string]string]和 Response[any]是两个不同类型的参数
    0 0
  • jorneyr
    2023年1月28日 03:26
    谢谢,返回前调用这个方法转换一下能满足要求。
    0 0
  • jorneyr
    2023年1月28日 03:26
    Java 的范型 ? 可以接收任意类型的,就想看看 Go 里能不能也用相似的办法实现。
    0 0
  • kaf
    2023年1月28日 03:26
    func foo[T any](in T) Response[T] { // [1] 创建范型对象 rsp1 := Response[T]{ Code: 200, Success: true, Data: in, } return rsp1 } 你是说这样的功能吗,go 的泛型使用就是你确定入参和返回类型的情况下
    0 0
  • jorneyr
    2023年1月28日 03:56
    // 像下面这样,接收 Response[string], Response[int] 等任意类型的范型参数进行统一处理。 // 业务代码里可能生成 Response[string], Response[AgentStats] 等不同类型的响应对象,这些对象都会在下面的 responseCommonHandle 函数中统一处理例如某些情况下打印日志。 func responseCommonHandle(rsp Rsponse[any]) { }
    0 0
  • OuJin
    2023年1月28日 03:56
    func main() { // 返回数据 var ( response1 = Response[map[string]string]{} // 返回 1, 数据类型 map[string]string response2 = Response[map[int]int]{} // 返回 2, 数据类型 map[int]int // ... ) // 模拟接收到的数据 var ( body1, _ = json.Marshal(response1) body2, _ = json.Marshal(response2) ) // 解析 var ( result1, err1 = foo[map[string]string](body1) // 指定 T 类型为 map[string]string result2, err2 = foo[map[int]int](body2) // 指定 T 类型为 map[int]int ) fmt.Println(result1, err1) fmt.Println(result2, err2) } func foo[T any](body []byte) (response Response[T], err error) { err = json.Unmarshal(body, &response) return } 在调用 foo 时指定类型,看看这样满不满足要求
    0 0
  • jorneyr
    2023年1月28日 03:56
    谢谢,我的问题重点不是在序列化和反序列化方面 (提问的时候应该去掉,加上只是为了验证序列化功能在范型的时候可以正常使用)。 我的问题主要是在不知道 Go 里有没有一个像 Java 范型那样: 定一个范型类型,可以接收任意类型的范型对象,也就是下面这个例子: List<String> list1 = new LinkedList<>(); List<?> list2 = list1;
    0 0
  • bigboNed3
    2023年1月28日 03:56
    ``` // [4] 范型向上类型转换 // 相当于 Java 的范型用 ? 来接收任意类型的范型如 // List<String> list1 = new LinkedList<>(); // List<?> list2 = list1; rsp3 := Response[any]{Code: rsp2.Code, Success: rsp2.Success, Data: rsp2.Data} ```
    0 0
  • kaf
    2023年1月28日 03:56
    下面这段代码是否是你想要的功能 ``` package main // 定义一个结构体,Data 是一个泛型接口 type Response[T ResponseHandle] struct { Code int `json:"code"` // 业务逻辑相关的 code ,不是 HTTP Status Code Success bool `json:"success"` // 业务逻辑处理成功时为 true ,错误时为 false Msg string `json:"msg"` // 请求的描述 Data T `json:"data,omitempty"` // 请求的 payload } type ResponseHandle interface { log() } type AgentStats struct { Status int } func (r *AgentStats) log() { // do something } func main() { } // 输入泛型的 resp,在函数中执行相关的方法 func responseCommonHandle[T ResponseHandle](rsp Response[T]) { rsp.Data.log() } ```
    0 0
  • jorneyr
    2023年1月28日 03:56
    不是的,如果用接口的方式,每个类型都要实现接口,反而工作量更大了,只是想要一个纯粹的存放数据的结构体。
    0 0
  • lysS
    2023年1月28日 03:56
    T[any] 这种泛型没啥意义,还有进一步的性能损失,不如直接 any 断言
    0 0
  • kaf
    2023年1月28日 03:56
    那其实输出类型 T ,返回类型 T 即可,你应该使用 T 类型而不是使用 any ,any 只是封装的 interface 类型,go 的泛型并不是 Java 的泛型,Java 的所有对象继承于 Object ,在 go 中每个结构体都是单独的类型,并不能强转,而且你需要在函数定义是知道输入什么类型,类似于 interface 可以接受任意类型参数,而定义泛型之后,编译器知道了 interface 是你定义的泛型结构体中的一个
    0 0
  • kaf
    2023年1月28日 03:56
    可以看 go 实现 Java 的 stream 的 map 方法 // Map manipulates a slice and transforms it to a slice of another type. // Play: func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R { result := make([]R, len(collection)) for i, item := range collection { result[i] = iteratee(item, i) } return result }
    0 0
  • jorneyr
    2023年1月28日 06:29
    与你的思路还是不太一样的。
    0 0
  • exonuclease
    2023年1月28日 06:57
    Response<T>不能直接用吗 c#里面是可以的啊 比如这个函数 private static TValue getValue<Tkey,TValue>(KeyValuePair<Tkey,TValue> kvp) { return kvp.Value; }
    0 0
  • BeautifulSoap
    2023年1月28日 08:26
    Go 的泛型类型都必须经过实例化。泛型实例化之后的类型就成为了和 int, string, float32 这些类型一样确定的类型 你用 map[string]string 实例化泛型类型 Response[T] 的话,那么实例化之后的类型就是 Response[map[string]string]。用 any 实例化的话实例化得到的则是 Response[any]。编译器的类型检查是不会去关心你这泛型类型到底是怎么个结构的,所以你把一个 Response[map[string]string] 类型的变量赋值给另一个 Response[any] 类型的变量那肯定要报错(在编译器的眼里,这相当于你把 int 类型变量赋值给 string 变量一样) 有兴趣可以看看我之前写的关于泛型的教程,go 目前的泛型并不是完整功能的泛型,所以并不能做到其他教程里那样理所当然的事情
    0 0
  • BeautifulSoap
    2023年1月28日 08:26
    打错字“go 目前的泛型并不是完整功能的泛型,所以并不能做到其他语言里那样理所当然的事情”
    0 0