pointers - Dirección de un temporal en Go?
return temporary (5)
¿Cuál es la forma más limpia de manejar un caso como este?
func a() string {
/* doesn''t matter */
}
b *string = &a()
Esto genera el error:
no puede tomar la dirección de a ()
Según entiendo, Go automáticamente promueve una variable local al montón si se toma su dirección. Aquí está claro que se debe tomar la dirección del valor de retorno. ¿Cuál es una forma idiomática de manejar esto?
Al final, propone que Go le permita tomar la dirección de cualquier expresión, por ejemplo:
i,j := 1,2
var p *int = &(i+j)
println(*p)
El compilador Go actual imprime el error: cannot take the address of i + j
En mi opinión, permitir que el programador tome la dirección de cualquier expresión:
- No parece ser muy útil (es decir: parece tener una probabilidad muy pequeña de ocurrencia en los programas Go reales).
- Sería complicado el compilador y la especificación del lenguaje.
Parece contraproducente complicar el compilador y las especificaciones con poca ganancia.
Consulte la sección correspondiente de la especificación de idioma de Go . &
solo se puede usar en:
- Algo que es direccionable: variable, direccionamiento indirecto de puntero, operación de indexación de segmento, selector de campo de una estructura direccionable, operación de indexación de matriz de una matriz direccionable; O
- Un literal compuesto
Lo que tienes no es ninguno de esos, así que no funciona.
Ni siquiera estoy seguro de lo que significaría incluso si pudieras hacerlo. Tomando la dirección del resultado de una llamada de función? Por lo general, pasas un puntero de algo a alguien porque quieres que se pueda asignar a lo apuntado, y ves los cambios en la variable original. Pero el resultado de una llamada a función es temporal; nadie más lo "ve", a menos que primero se lo asigne a algo.
Si el propósito de crear el puntero es crear algo con una vida dinámica, similar a new()
o tomar la dirección de un literal compuesto, entonces puede asignar el resultado de la llamada de función a una variable y tomar la dirección de eso.
El operador de dirección devuelve un puntero a algo que tiene una "casa", por ejemplo, una variable. El valor de la expresión en tu código es "sin hogar". si realmente necesitas una * cadena, tendrás que hacerlo en 2 pasos:
tmp := a(); b := &tmp
Tenga en cuenta que si bien hay casos de uso completamente válidos para * cadena, muchas veces es un error usarlos. En Go string
es un tipo de valor, pero uno barato para pasar (un puntero y un int). El valor de la cadena es inmutable, cambiando una *string
cambia a donde apunta la "casa", no el valor de la cadena, por lo que en la mayoría de los casos *string
no es necesaria en absoluto.
Hace poco estuve atada en nudos por algo similar.
Primero hablar sobre cadenas en su ejemplo es una distracción, usar una estructura en su lugar, volver a escribirla en algo como:
func a() MyStruct {
/* doesn''t matter */
}
var b *MyStruct = &a()
Esto no compilará porque no puede tomar la dirección de a (). Entonces haz esto:
func a() MyStruct {
/* doesn''t matter */
}
tmpA := a()
var b *MyStruct = &tmpA
Esto se compilará, pero has devuelto un MyStruct en la pila, asignado suficiente espacio en el montón para almacenar un MyStruct, y luego copiado el contenido de la pila al montón. Si quieres evitar esto, escríbelo así:
func a2() *MyStruct {
/* doesn''t matter as long as MyStruct is created on the heap (e.g. use ''new'') */
}
var a *MyStruct = a2()
La copia es normalmente económica, pero esas estructuras pueden ser grandes. Peor aún cuando quiere modificar la estructura y hacer que ''pegue'' no puede copiar y luego modificar las copias.
De todos modos, se vuelve aún más divertido cuando estás usando un tipo de interfaz de retorno {}. La interfaz {} puede ser la estructura o un puntero a una estructura. El mismo problema de copiado surge.
a()
no apunta a una variable como está en la pila. No puedes apuntar a la pila (¿por qué lo harías?).
Puedes hacer eso si quieres
va := a()
b := &va
Pero lo que realmente quieres lograr es algo confuso.