du4822 2017-02-04 11:29
浏览 50
已采纳

Golang指针之间的区别

There are 2 kinds of variables that I have. Check for the Go playground, and I don't understand why this is happening. The problem: what I get from the Models it should be a struct to use it for GORM First() function.

The code:

package main

import (
    "fmt"
)

type Test struct {
    Test string
}

var Models = map[string]interface{}{
    "test": newTest(),
}

func main() {
    test1 := Test{}
    fmt.Println("Test 1: ")
    fmt.Printf("%v", test1)
    fmt.Println()
    fmt.Println("Test 1 as pointer: ")
    fmt.Printf("%v", &test1)
    fmt.Println()
    test2 := Models["test"]
    fmt.Println("Test 2: ")
    fmt.Printf("%v", test2)
    fmt.Println()
    fmt.Println("Test 2 as pointer: ")
    fmt.Printf("%v", &test2)

}

func newTest() Test {
    var model Test 
    return model
}
  • 写回答

2条回答 默认 最新

  • doutang6130 2017-02-04 16:26
    关注

    TL;DR: In the first case you pass a value of type *Test for printing, but in the second case you pass a value of type *interface{}! The %v verb means to format using the default formatting, but the default formatting depends on the type of the value.


    The difference you see is just the default formatting rules of the fmt package's implementation.

    You're using fmt.Printf():

    func Printf(format string, a ...interface{}) (n int, err error)
    

    which takes a format string and other arguments as type interface{}. So note that if the value you pass is not of type interface{}, the value will be wrapped in a value of type interface{}.

    Now let's see your examples:

    test1 := Test{}
    // ...
    fmt.Printf("%v", &test1)
    

    test1 is of type Test, and you pass &test1 which is of type *Test. This will be wrapped in an interface{}. The formatting rules from the package doc of fmt:

    For compound objects, the elements are printed using these rules, recursively, laid out like this:

    struct:             {field0 field1 ...}
    array, slice:       [elem0 elem1 ...]
    maps:               map[key1:value1 key2:value2]
    pointer to above:   &{}, &[], &map[]
    

    Since it is a pointer to a struct, the &{} format will be used. Test has a field Test string, but you didn't set its value, so it defaults to the zero value of the type string which is the empty string "". That's why you see nothing when displayed. Note that if you would have initialized it like this:

    test1 := Test{"a"}
    

    The output would have been:

    &{a}
    

    Let's see your 2nd example:

    test2 := Models["test"]
    // ...
    fmt.Printf("%v", &test2)
    

    The first line is a short variable declaration, type of test2 will be inferred from the right-hand side expression. The right hand side expression is an index expression, indexing a map. Its type will be the value type of the map, and since type of Models is map[string]interface{}, type of test2 will be interface{}.

    So far so good. But what happens when you try to print it like fmt.Printf("%v", &test2)? You pass a pointer to test2 which is of type interface{}, so what you pass is of type *interface{}, and since this is not identical to interface{}, it will be wrapped in another interface{} value.

    So what gets passed to fmt.Printf() is an interface{} value, wrapping a *interface{} value being the address of the test2 variable.

    And now the formatting rule that applies here:

    The default format for %v is:

    bool:                    %t
    int, int8 etc.:          %d
    uint, uint8 etc.:        %d, %x if printed with %#v
    float32, complex64, etc: %g
    string:                  %s
    chan:                    %p
    pointer:                 %p
    

    Since the value to be formatted is a pointer (*interface{}), %v will default to %p, which is:

    Pointer:

    %p    base 16 notation, with leading 0x
    

    So the result is properly printing the address value in hexadecimal format, e.g.:

    0x1040a160
    

    To obtain a struct from test2, you can use type assertion. So it should rather be something like this:

    t2 := Models["test"]
    test2 := t2.(Test) // test2 is of type Test
    

    This test2 has identical type to that of test1, and will produce the same result when printing. Try it on the Go Playground.

    Best would be though to store *Test values in the map, and so no type assertion or even storing in local variable would be necessary, as the interface{} stored in the map would already be a pointer to Test, which can be used / passed around as-is.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?