douren5898 2018-03-20 21:32 采纳率: 100%
浏览 73
已采纳

类型断言会改变go中的值吗?

Go newbie here.

I have a map where the key arguments should be []string.

However, if I try to use the value directly arguments := m["arguments"] it doesn't seem to be the right type. When used later to append to another slice with arguments... I get Cannot use 'arguments' (type interface{}) as type []string.

I fixed this by chaning the assignment to a type check arguments, _ := m["arguments"].([]string). That works, but I'm not sure why. Is type assertion doing conversion as well?

The full example is below:

import (
    "github.com/fatih/structs"
    "strings"
)

var playbookKeyDict = map[string]string{
    "Playbook": "",
    "Limit" : "--limit",
    "ExtraVars" : "--extra-vars",
}

type Playbook struct {
    Playbook string `json:"playbook" xml:"playbook" form:"playbook" query:"playbook"`
    Limit string `json:"limit" xml:"limit" form:"limit" query:"limit"`
    ExtraVars string `json:"extra-vars" xml:"extra-vars" form:"extra-vars" query:"extra-vars"`
    Arguments []string `json:"arguments" xml:"arguments" form:"arguments" query:"arguments"`
    Args []string
}

func (p *Playbook) formatArgs() {
    // is it worth iterating through directly with reflection instead of using structs import?
    // https://stackoverflow.com/questions/21246642/iterate-over-string-fields-in-struct
    m := structs.Map(p)

    // direct assignment has the wrong type?
    // arguments := m["arguments"]
    arguments, _ := m["arguments"].([]string)
    delete(m, "arguments")

    for k, v := range m {
        // Ignore non-strings and empty strings
        if val, ok := v.(string); ok && val != "" {
            key := playbookKeyDict[k]
            if key == "" {
                p.Args = append(p.Args, val)
            } else {
                p.Args = append(p.Args, playbookKeyDict[k], val)
            }
        }
    }
    p.Args = append(p.Args, arguments...)
}
  • 写回答

1条回答 默认 最新

  • dougu5886 2018-03-20 21:43
    关注

    Type assertion is used to get a value wrapped around using interface.

    m := structs.Map(p)
    
    Map(v interface{}){}
    

    Map function is actually taking interface as its argument in the case stated. It is wrapping the type which is []string and its underlying value which is slice. The type can be checked using Relection reflect.TypeOf().

    func TypeOf(i interface{}) Type
    

    According to Russ Cox blog on Interfaces

    Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to the associated data.

    As specified in Golang spec

    For an expression x of interface type and a type T, the primary expression

    x.(T)
    

    asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.

    For the error part:-

    Cannot use 'arguments' (type interface{}) as type []string
    

    We first needs to get the underlying value of type []string from interface using type assertion.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料