2012-01-07 37 views
6

En el lenguaje de programación Go; ¿Cómo pueden ser útiles los punteros a los indicadores?¿Para qué sirven los punteros?

(¿Por qué no ilegal si no son realmente útiles?)

+6

Puntero a cualquier dato útil. Los punteros son datos. Así que los punteros a los punteros son útiles, y también lo son los punteros a punteros, ... –

+0

Estoy de acuerdo, pero dado que no hay aritmética de puntero ni nada que ver con punteros más que punteros en Go, de hecho son un poco inútiles. – thwd

+0

Hay una aritmética de puntero en Go. Puede usar el paquete 'inseguro' para obtener un' uintptr' que puede usar libremente. En algunos casos, este enfoque puede conducir a un código más eficiente, pero en general, debe evitarse. – tux21b

Respuesta

16

La utilidad de cualquier tipo de datos depende del problema a resolver y del método utilizado para resolver el problema. Si un tipo de datos no se ajusta al problema, simplemente no se ajusta al problema, y ​​no hay nada más.

El lenguaje de programación Go (así como la mayoría de los demás lenguajes de programación) se basa en reglas simples que el programador puede usar para crear nuevos tipos de datos. Algunas de estas reglas son:

  • *T: crear un nuevo tipo de datos que es un puntero a T
  • [10]T: una matriz de Ts
  • struct { t T; u U ... }: una estructura que contiene una T como un componente
  • ...

El programador puede crear tipos de datos complejos mediante la composición de estas sencillas reglas. La cantidad total de tipos de datos posibles excede la cantidad de tipos de datos útiles. Claramente, existen (y deben existir) tipos de datos que no son útiles en absoluto. Esto es solo una consecuencia natural del hecho de que las reglas para construir nuevos tipos de datos son simples.

El tipo **T entra en la categoría de tipos que son menos probables de aparecer en un programa. El hecho de que sea posible escribir *****T no implica que dicho tipo tenga que ser inmensamente útil.


Y, por último, la respuesta a su pregunta:

El tipo **T suele aparecer en contextos en los que queremos redirigir a los usuarios de un valor de tipo T a otro valor de tipo T, pero para alguna razón por la que no tiene acceso a todos los usuarios del valor o la búsqueda de los usuarios costaría demasiado tiempo:

  1. no queremos copiar valores de tipo T (por alguna razón)
  2. Queremos que todos los usuarios de un valor de tipo T para acceder al valor a través de un puntero
  3. Queremos rápidamente redirigir todos usuarios de un determinado valor de tipo T a otro valor

en tal situación, el uso de **T es natural, ya que nos permite implementar la tercera etapa en O (1):

type User_of_T struct { 
    Value **T 
} 

// Redirect all users of a particular value of type T 
// to another value of type T. 
func (u *User_of_T) Redirect(t *T) { 
    *(u.Value) = t 
} 
+0

Esa es una solución inteligente, sin embargo. – Tarik

3

En C, los punteros a los punteros son bastante comunes.Por ejemplo: arrays

  • más dimensionales (por ejemplo una matriz de cadenas, char** argv podría ser el ejemplo más destacado aquí)
  • punteros como parámetros de salida

En Go sin embargo, punteros a punteros son Bastante raro. En lugar de acceder a las matrices con un puntero, hay un tipo de sector (que también almacena un puntero internamente). Por lo tanto, aún puede obtener el mismo tipo de indirección mediante el uso de una porción de sectores en Ir, pero normalmente no verá algo como **int aquí.

Sin embargo, el segundo ejemplo podría aplicarse a los programas Go. Supongamos que tiene una función que debería poder cambiar un puntero pasado como parámetro. En ese caso, deberá pasar un puntero a ese puntero para que pueda cambiar el puntero original. Eso es extremadamente común en C, porque las funciones solo pueden devolver un valor (que a menudo es algún tipo de código de error) y si desea devolver un puntero adicional, deberá usar un puntero a ese puntero como parámetro de salida. Sin embargo, una función en Go puede devolver múltiples valores, por lo que las ocurrencias de punteros a punteros también son raras. Pero aún podrían ser útiles y, en algunos casos, podrían conducir a una API más agradable.

Por ejemplo, la función atomic.StorePointer puede ser uno de esos casos de uso raros pero bien escondidos para punteros a punteros en la biblioteca estándar.

5

Cuando pasa un puntero a la función, la función obtiene una copia de la misma. Así asignar un nuevo valor al puntero, dados no dará lugar a asignarlo a la original:

type Smartphone struct { 
    name string 
} 

type Geek struct { 
    smartphone *Smartphone 
} 

func replaceByNG(s **Smartphone) { 
    *s = &Smartphone{"Galaxy Nexus"} 
} 

func replaceByIPhone(s *Smartphone) { 
    s = &Smartphone{"IPhone 4S"} 
} 

func main() { 
    geek := Geek{&Smartphone{"Nexus S"}} 
    println(geek.smartphone.name) 

    replaceByIPhone(geek.smartphone) 
    println(geek.smartphone.name) 

    replaceByNG(&geek.smartphone) 
    println(geek.smartphone.name) 
} 

la salida es:

Nexus S 
Nexus S 
Galaxy Nexus 
+0

la respuesta realmente útil, esto es lo que encontré tratando de modificar slice en otra función –

2

Linus Torvalds mencionó recientemente cómo punteros a punteros llevan a codificar con buen gusto (en C). Ver (entre otros) Brian Barto's blog post.

Cuestiones relacionadas