登录
首页 >  Golang >  Go问答

可以将任意类型的实例赋值给任意类型的值吗?

来源:stackoverflow

时间:2024-03-01 15:54:26 452浏览 收藏

来到golang学习网的大家,相信都是编程学习爱好者,希望在这里学习Golang相关编程知识。下面本篇文章就来带大家聊聊《可以将任意类型的实例赋值给任意类型的值吗?》,介绍一下,希望对大家的知识积累有所帮助,助力实战开发!

问题内容

是否可以确定(使用 reflect)任意类型的实例是否可以设置为任意值,即确定 value.set() 是否会因类型不兼容而发生恐慌?

下面列出了 mcve。我想知道的是“我可以在不使用 defer/recover 构造的情况下编写 set() 吗?”

我想避免 defer ,不仅因为它看起来很难看,而且因为 value.set() 可能会因其他原因而恐慌。

请注意,这不仅仅是比较类型是否相等的问题,如下面的 o2 示例所示。

package main

import (
    "fmt"
    "reflect"
)

// set a value V to interface i, returning true if this can be done, else false
//
// CAN WE WRITE THIS WITHOUT HAVING TO USE DEFER / RECOVER?
//
func set(v reflect.Value, i interface{}) bool {
    success := true
    defer func() {
        if r := recover(); r != nil {
            success = false
        }
    }()
    v.Set(reflect.ValueOf(i))
    return success
}

// get the type of a typed nil
func getType(typedNil interface{}) reflect.Type {
    return reflect.TypeOf(typedNil).Elem()
}

func main() {
    t1 := getType((*int)(nil))
    o1 := reflect.New(t1)

    t2 := getType((*interface{})(nil))
    o2 := reflect.New(t2)

    var ok bool
    var aInt = 456
    var aString string = "hello"
    var aUint uint = 123

    // Set o1 to various types
    
    ok = set(o1.Elem(), aInt) // Should return true
    fmt.Printf("After o1 set to aInt returned %v: obj is type %T content '%v'\n", ok, o1.Elem().Interface(), o1.Elem().Interface())

    ok = set(o1.Elem(), aString) // Should return false
    fmt.Printf("After o1 set to aString returned %v: obj is type %T content '%v'\n", ok, o1.Elem().Interface(), o1.Elem().Interface())

    ok = set(o1.Elem(), aUint) // Should return false
    fmt.Printf("After o1 set to aUint returned %v: obj is type %T content '%v'\n", ok, o1.Elem().Interface(), o1.Elem().Interface())

    fmt.Println("")

    // Set o2 to various types
    ok = set(o2.Elem(), aInt)  // Should return true
    fmt.Printf("After o2 set to aInt returned %v: obj is type %T content '%v'\n", ok, o2.Elem().Interface(), o2.Elem().Interface())

    ok = set(o2.Elem(), aString) // Should return true
    fmt.Printf("After o2 set to aString returned %v: obj is type %T content '%v'\n", ok, o2.Elem().Interface(), o2.Elem().Interface())
    
    ok = set(o2.Elem(), aUint) // Should return true
    fmt.Printf("After o2 set to aUint returned %v: obj is type %T content '%v'\n", ok, o2.Elem().Interface(), o2.Elem().Interface())
}


解决方案


reflect.Type 有一个 type.assignableto() 方法:

// assignableto reports whether a value of the type is assignable to type u.
assignableto(u type) bool

因此您可以使用它来简化您的 set() 函数:

func set(v reflect.value, i interface{}) bool {
    if !reflect.typeof(i).assignableto(v.type()) {
        return false
    }
    v.set(reflect.valueof(i))
    return true
}

输出将是相同的(在 Go Playground 上尝试):

After o1 set to aInt returned true: obj is type int content '456'
After o1 set to aString returned false: obj is type int content '456'
After o1 set to aUint returned false: obj is type int content '456'

After o2 set to aInt returned true: obj is type int content '456'
After o2 set to aString returned true: obj is type string content 'hello'
After o2 set to aUint returned true: obj is type uint content '123'

您还可以(另外)致电Value.CanSet()来检测某些“不可设置”的情况:

canset 报告 v 的值是否可以更改。仅当 value 是可寻址的并且不是通过使用未导出的结构字段获取时才可以更改 value。如果 canset 返回 false,则调用 set 或任何特定于类型的 setter(例如 setbool、setint)将会出现恐慌。

今天关于《可以将任意类型的实例赋值给任意类型的值吗?》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>