dougong5817 2014-08-28 14:17
浏览 70
已采纳

您将如何访问传递给在Go中期望一个空接口的函数的基础数组?

So let's say that we have a function of the following form:

func WorkMagic(obj interface{}) interface{} {
    switch t := obj.(type) { 
    case string:
        // Do string magic
    default:
        // Do slice magic
    }
    ...
}

I am expecting obj to be either a string or a slice, which I can ascertain via the switch. In the case of a slice, I want to be able to do ordering work on any arbitrary slice, regardless of type. Seems like the best way to accomplish this is using the unsafe package in a similar fashion to that discussed in this article.

Here however, the function accepts a specific type of slice ([]string), whereas I would like to be able to work on any slice. So the question is, given that I am accepting an empty interface as input, how might I access the underlying slice / array using unsafe.Pointer so as to be able to loop through and modify which value is associate with which index?

  • 写回答

1条回答 默认 最新

  • dpd3447 2014-08-28 14:49
    关注

    You'll want to use reflection. It enables you to work generically without giving up type and memory safety like unsafe would. Read the Go blog's Laws of Reflection.

    func actOnSlices(i interface{}) {
    
        v := reflect.ValueOf(i)
    
        for v.Kind() == reflect.Ptr { // dereference pointers
            v = v.Elem()
        }
    
        if v.Kind() != reflect.Slice { // ensure you actually got a slice
            panic("given argument is not a slice")
        }
    
        // do slice stuff
    
    }
    

    Edit to answer your second question:

    Yes – this can be done: elements of a slice are adressable and hence settable. See the following working example:

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        s := []string{"foo", "bar"}
        fmt.Println(swapIndexes(s, 0, 1)) // prints [bar foo]
    }
    
    func swapIndexes(i interface{}, x, y int) interface{} {
    
        v := reflect.ValueOf(i)
    
        for v.Kind() == reflect.Ptr { // dereference pointers
            v = v.Elem()
        }
    
        if v.Kind() != reflect.Slice { // ensure you actually got a slice
            panic("given argument is not a slice")
        }
    
        t := v.Index(x).Interface()
    
        v.Index(x).Set(v.Index(y))
    
        v.Index(y).Set(reflect.ValueOf(t))
    
        return v.Interface()
    
    }
    

    Edit to answer your third question:

    The unsafe package is not something you'll encounter much in user-land code. It exists to implement certain features (e.g. reflection, C interaction) that need to circumvent Go's safety guarantees to work. Using unsafe is unsafe, as the name suggests, because you can mess up big time without even realizing. By using unsafe, you're incurring in a big trade-off, so it better be worth it. Quoting @twotwotwo:

    The downside of unsafe is that if you mess up you're in the old days of segfaults, memory corruption, and buffer-overflow security holes.

    Also, as @twotwotwo suggested; it's more "Go-like" to repeat code than using reflection to achieve genericity.

    To Go's type-system, []string and []int are two completely separate and unrelated types. just as int and string would be. The relation (both are slices) is obvious only to the programmer. There is no way of expressing "a slice" without saying a slice of what.

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

报告相同问题?

悬赏问题

  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!