当前位置: 首页 > 面试题库 >

Go中的通用编程。避免硬编码类型断言

莫誉
2023-03-14
问题内容

我正在编程一个通用的缓存机制,我需要在结构中设置一些属性,这些结构只知道它们的reflect.Type,属性名称和reflect.Value可以在属性中设置,但我无法避免类型断言,这使得我的代码不是通用的…

func main() {
    addressNew := Address{"New Address description!"}

    // In the real problem, i know the reflect.Type of value, but
    // the struct came to me as a interface{}, just like this method
    // Return many kinds of values from redis as interface{}, 
    // (Customer, Order, Address, Product, SKU etc), in a generic way,
    // but returns the reflect.Type of value also.
    interfaceSomeValue := getMyValue()

    fmt.Printf("%v", interfaceSomeValue)
    fmt.Println("")

    // This portion of code comes from my cache mechanism, that is a library 
    // used by other projects. My cache lib really can't know all others
    // type structs to perform the type assertion, but the cache mechanism know 
    // the reflect.Type of the interface. 
    // If you try at this way, will cause a panic by try to access a FieldByName
    // in a interface, because the Customer comes from getMyValue and 
    // becomes a interface{}, and now a type assertion is 
    // required -> http://play.golang.org/p/YA8U9_KzC9
    newCustomerNewAttribute := SetAttribute(&interfaceSomeValue, "Local", interface{}(addressNew), reflect.TypeOf(Customer{}))

    fmt.Printf("%v", newCustomerNewAttribute)
    fmt.Println("")
}

func SetAttribute(object interface{}, attributeName string, attValue interface{}, objectType reflect.Type) interface{} {
    if reflect.ValueOf(object).Kind() != reflect.Ptr {
        panic("need a pointer")
    }

    value := reflect.ValueOf(object).Elem()
    field := value.FieldByName(attributeName)
    valueForAtt := reflect.ValueOf(attValue)
    field.Set(valueForAtt)
    return value.Interface()
}

前往Playground解决问题(通过硬编码类型断言工作)…

前往Playground解决问题(不适用于未知界面)


问题答案:

最终,我找到了一种方法。请遵循下面的Go Playground和代码段:

前往游乐场:避免硬编码类型声明

//new approach SetAttribute, without any hard coded type assertion, just based on objectType parameter
func SetAttribute(myUnknownTypeValue *interface{}, attributeName string, attValue interface{}, objectType reflect.Type) {

    // create value for old val
    oldValue := reflect.ValueOf(*myUnknownTypeValue)

    //create a new value, based on type
    newValue := reflect.New(objectType).Elem()
    // set the old value to the new one, making the 
    // implicit type assertion, not hard coding that.
    newValue.Set(oldValue)

    //set value attribute to the new struct, copy of the old one
    field := newValue.FieldByName(attributeName)
    valueForAtt := reflect.ValueOf(attValue)
    field.Set(valueForAtt)

    //capture the new value from reflect.Value
    newValInterface := newValue.Interface()
    //set the new value to the pointer
    *myUnknownTypeValue = newValInterface
}


 类似资料:
  • 问题内容: 问: 在SQL脚本或存储过程中,避免幻数或硬编码值还有哪些其他策略? 考虑一个存储过程,该存储过程的工作是根据其或某些其他FK查找表或值的范围来检查/更新记录的值。 考虑一个表,其中ID最重要,因为它是另一个表的FK: 应避免的SQL脚本 如下所示 : 这里的问题是,这不是可移植的,并且显式依赖于硬编码的值。在将其部署到另一个没有标识插入的环境时,存在细微的缺陷。 还尝试避免基于文本的

  • 问题内容: 我在Go中使用类型开关,例如以下代码: 有没有一种方法可以防止在将问题传递给另一个函数之前必须断言案件中的问题类型? 问题答案: 是的,分配类型切换的结果将为您提供断言的类型 http://play.golang.org/p/qy0TPhypvp

  • 我开发了一个Atlasian Bitbucket插件,它在全局上监听push/pr并使用REST API向数据库发送存储库详细信息。 我需要配置和,以便我的插件可以进行API调用。目前,我的插件属性文件中有和。我不喜欢这样做,因为每次如果我需要创建一个包来针对我的测试环境或生产,我都必须进行更改。此外,我不喜欢在源代码中保留凭据。 在bitbucket插件中添加配置屏幕的最佳方法是什么?我想有一个

  • 问题内容: 我有一个PostgreSQL的AWS RDS实例,在该实例中,我需要使用并且以该角色(我创建的)登录时在函数内执行一条语句。 的是生产以下错误消息: 我找到了建议使用的答案。当我尝试这样做时,我收到以下错误消息: 在AWS上,如何授予创建RDS实例的用户执行功能的权限?我尝试了以下操作,但未成功: 看来我的用户需要我显然无法在AWS上获得的权限。 我也曾使用(在Windows上)提供密

  • 问题内容: 我正在尝试一些go编程语言。 我对Go的简单性感到很兴奋,但是在使用它后我遇到了一些麻烦。 1。我知道 Go 不支持泛型和继承。 有什么办法可以实现泛型列表? 我在考虑使用: 但是如何检查该值是否为NULL。 我正在寻找与C等效的实现 或使用代数数据类型: 2。更高级的要求是为 具有特定类型字段的对象创建一些容器? 例如,在 Scala编程语言中, 我可以输入: 获得的,其成员类型为

  • 在 Rust 中,任何值都属于一种明确的 类型(type),这告诉了 Rust 它被指定为何种数据,以便明确其处理方式。本部分我们将看到一系列内建于语言中的类型。我们将其分为两类:标量(scalar)和复合(compound)。 Rust 是 静态类型(statically typed)语言,也就是说在编译时就必须知道所有变量的类型,这一点将贯穿整个章节。通过值的形式及其使用方式,编译器通常可以推