string go null optional variant

string - ¿Cómo represento una cadena opcional en Go?



null optional (2)

Deseo modelar un valor que puede tener dos formas posibles: ausente o una cadena.

La forma natural de hacerlo es con Maybe String u Optional<String> , o la string option , etc. Sin embargo, Go no tiene tipos de variantes como este.

Entonces pensé, siguiendo a Java, C, etc., que la alternativa sería la capacidad de anulación, o nil en Go. Sin embargo, nil no es un miembro del tipo de string en Go.

Al buscar, pensé usar el tipo *string . Esto podría funcionar, pero parece muy incómodo (por ejemplo, no puedo tomar la dirección del literal de la cadena de la misma manera que puedo tomar la dirección de una estructura literal).

¿Cuál es la forma idiomática de modelar tal valor en Go?


Podrías usar algo como sql.NullString , pero personalmente me quedaría con *string . En cuanto a la incomodidad, es cierto que no se puede simplemente sp := &"foo" desgracia. Pero hay una solución para esto:

func strPtr(s string) *string { return &s }

Las llamadas a strPtr("foo") deben estar en línea, por lo que es eficaz &"foo" .

Otra posibilidad es usar new :

sp := new(string) *sp = "foo"


Una solución lógica sería usar *string como lo menciona Ainar-G. Esta otra respuesta detalla las posibilidades de obtener un puntero a un valor ( int64 pero lo mismo también funciona con la string ). Un contenedor es otra solución.

Usando solo string

Una string opcional significa una string más 1 valor específico (o estado) que dice "no una cadena" (sino un null ).

Este 1 valor específico se puede almacenar (señalizar) en otra variable (por ejemplo, bool ) y puedes empaquetar la string y el bool en una struct y llegamos al contenedor, pero esto no encaja en el caso de "usar solo una string "(pero sigue siendo una solución viable).

Si queremos apegarnos solo a una string , podemos sacar 1 valor específico de los posibles valores de un tipo de string (que tiene valores posibles de "infinito" ya que la longitud no está limitada (o tal vez es como debe ser una int pero eso está bien)), y podemos nombrar este valor específico como el valor null , el valor que significa "no una cadena".

El valor más conveniente para indicar null es el valor cero de la string , que es la string vacía: "" . Al designar esto, el elemento null tiene la conveniencia de que cada vez que cree una variable de string sin especificar explícitamente el valor inicial, se inicializará con "" . Además, al consultar un elemento de un map cuyo valor es una string también arrojará "" si la clave no está en el map .

Esta solución se adapta a muchos casos de uso de la vida real. Si se supone que la string opcional es el nombre de una persona, por ejemplo, una string vacía realmente no significa un nombre de persona válido, por lo que no debe permitir eso en primer lugar.

Puede haber casos, por supuesto, cuando la string vacía representa un valor válido de una variable del tipo de string . Para estos casos de uso, podemos elegir otro valor.

En Go, una string es en efecto una porción de bytes de solo lectura. Consulte la publicación del blog Cadenas, bytes, runas y caracteres en Ir que explica esto en detalle.

Por lo tanto, una string es un segmento de bytes, que es el byte codificado UTF-8 en el caso de un texto válido. Suponiendo que desea almacenar un texto válido en su string opcional (si no lo hace, entonces puede usar un []byte lugar que puede tener un valor nil ), puede elegir un valor de string que represente un UTF-8 no válido secuencia de bytes y por lo tanto ni siquiera tendrá que hacer un compromiso para excluir un texto válido de los posibles valores. La secuencia de bytes UTF-8 inválida más corta es de 1 byte solamente, por ejemplo 0xff (hay más). Nota: puede usar la función utf8.ValidString() para indicar si un valor de string es un texto válido (secuencia de bytes codificada en UTF-8 válida).

Puedes hacer de este valor excepcional una const :

const Null = "/xff"

Ser tan corto también significa que será muy rápido comprobar si una string es igual a esto.
Y según esta convención, usted ya tiene una string opcional que también permite la string vacía.

Pruébalo en el patio de juegos Go .

const Null = "/xff" func main() { fmt.Println(utf8.ValidString(Null)) // false s := Null fmt.Println([]byte(s)) // [255] fmt.Println(s == Null) // true s = "notnull" fmt.Println(s == Null) // false }