How can I "cast" a pointer type in Go to match the type of the pointed-to value?

huangapple go评论74阅读模式
英文:

How can I "cast" a pointer type in Go to match the type of the pointed-to value?

问题

我有一个包含不同变量类型的切片,包括字符串、整数等。有没有办法将*interface{}指针根据需要转换为*string*int32类型的指针。

这里有一个示例程序演示了这个问题:http://play.golang.org/p/J3zgrYyXPq

// 在切片中存储一个字符串
valSlice := make([]interface{}, 1)
var strVal string = "test"
valSlice[0] = strVal

// 创建指向该字符串的指针
ptrToStr := &valSlice[0]

// 输出 "string vs *interface {}"
fmt.Printf("%T vs %T\n", valSlice[0], ptrToStr) 

// 尝试1(无法编译通过):
// ----------------------------
// 我该如何将指针类型转换为(*string),并引用与strVal相同的内存位置?
// 这段代码无法编译通过:
//var castPtr *string = &valSlice[0].(string)

// 尝试2(断言后,指针不指向相同的内存位置):
var sureType string = valSlice[0].(string)
var castPtr *string = &sureType
*castPtr = "UPDATED"
fmt.Println(valSlice[0]) // 输出 "test",而不是 "UPDATED"

如果我需要解释我想要这样做的原因,这里是解释。database/sql包在扫描值时会查看指针类型。我的代码已经准备了一个切片,其中包含了正确类型的零值变量,以匹配结果集。

因为Scan需要指针,所以我遍历我的切片,并构建一个指向原始切片中变量的指针切片。然后将这个指针切片传递给Scan函数。但是,由于上述创建指针的操作会导致一个*interface{}指针,而不是与变量类型匹配的指针,所以Scan函数无法知道底层数据类型,无法将原始的[]byte值转换为正确的类型。

英文:

I have a slice that contains different variable types. Some strings, integers, etc. Is there any way for me to "cast" a pointer to one of these values from *interface{} to *string or *int32 where appropriate.

Here is a toy program that demonstrates the issue: http://play.golang.org/p/J3zgrYyXPq

// Store a string in the slice
valSlice := make([]interface{}, 1)
var strVal string = "test"
valSlice[0] = strVal

// Create a pointer to that string
ptrToStr := &valSlice[0]

// Outputs "string vs *interface {}"
fmt.Printf("%T vs %T\n", valSlice[0], ptrToStr) 

// Attempt 1 (doesn't compile):
// ----------------------------
// How can I cast the pointer type to (*string), referencing the same
// memory location as strVal?
// This doesn't compile:
//var castPtr *string = &valSlice[0].(string)

// Attempt 2 (after assertion, doesn't point to the same memory location):
var sureType string = valSlice[0].(string)
var castPtr *string = &sureType
*castPtr = "UPDATED"
fmt.Println(valSlice[0]) // Outputs "test", not "UPDATED"

If I need to justify my desire to do this, here's the explanation. The database/sql package looks at the pointer type when scanning values. My code has already prepared a slice holding zero-valued variables of the correct types to match the resultset.

Because Scan requires pointers, I iterate over my slice and build a new slice of pointers to the variables in my original slice. I then pass this slice of pointers into the Scan. But because the act of creating a pointer as above results in an *interface{} pointer instead of one that matches the variable type, the Scan does not know the underlying datatype to convert the raw []byte value to.

答案1

得分: 2

你必须知道,当一个变量被赋值给一个接口时,会发生什么?

str := "hello world"
var tmp interface{} = str

编译器会创建一个临时对象,该对象的值与 str 相同,并将 tmp 与之关联。因此,在此之后,对 tmp 所做的任何操作都与 str 无关。但是 Go 不允许你更改临时对象。所以你不能在接口中解引用临时对象,也不能更改它,这就是错误存在的原因。如果你想了解更多关于接口实现的信息,请阅读 http://research.swtch.com/interfaces

如果你想改变原始对象,可以将指针传递给接口:

valSlice := make([]interface{}, 1)
var strVal string = "test"
valSlice[0] = &strVal // 将指针传递给接口
var castPtr *string = valSlice[0].(*string) // 获取指针
*castPtr = "UPDATED" // 改变字符串 strVal
fmt.Println(strVal) // 输出 "UPDATED"
英文:

1 You must know , when a var is assigned to a interface , what happend ?

str := "hello world"
var tmp interface{} = str

the complier will create a tempotary object , which has the same value with str ,and tmp is associated with it. So after that , all you do to tmp is not associated with str. But go doesn't allow you to change the tempotary object。 So you can't have the dereference of the tempotary object in interface and you can't change it, that's why the errors exist. If you want more information about the implements of interface, read http://research.swtch.com/interfaces

2 If you want change the original object, pass the pointer to a interface

valSlice := make([]interface{}, 1)
var strVal string = "test"
valSlice[0] = &strVal //pass a pointer to a interafce
var castPtr *string = valSlice[0].(*string) // get the pointer
*castPtr = "UPDATED"//change the string strVal
fmt.Println(strVal) // Outputs "UPDATE"

huangapple
  • 本文由 发表于 2014年9月16日 09:05:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/25859199.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定