Menu

Operador ternario en Golang: por qué Go no lo tiene y qué usar

Go no tiene operador ternario (cond ? a : b). Esta página explica por qué, muestra el sustituto idiomático con if/else, cmp.Or para valores por defecto y una función genérica auxiliar, junto con la trampa que la hace distinta de un ternario de verdad.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Go no tiene operador ternario. No existe cond ? a : b. El sustituto idiomático es una sentencia if:

Declara la variable con el valor por defecto y cámbiala en el if. Cuando las dos ramas necesitan trabajo, usa if/else:

var fee int
if member {
	fee = 0
} else {
	fee = computeFee(order)
}

Por qué Go lo dejó fuera

Las FAQ de Go lo responden directamente: los diseñadores habían visto el operador ?: usado demasiadas veces para crear expresiones complejísimas e impenetrables, y decidieron que if/else, aunque más largo, es sin duda más claro. Un lenguaje solo necesita una construcción de control de flujo condicional.

En la práctica, el operador que falta cuesta dos o tres líneas por uso y elimina toda una categoría de expresiones anidadas como a ? b ? c : d : e.

Retornar pronto

Dentro de una función, la forma más limpia a menudo se salta la variable por completo:

Llevar la condición a una pequeña función con nombre suele ser la mejor respuesta: la llamada se lee como el ternario que querías, y el nombre de la función documenta qué significa la condición.

Valores por defecto con cmp.Or (Go 1.22)

El ternario más común en otros lenguajes es "usa este valor, o uno de reserva si está vacío": name ? name : "anonymous", o name || "anonymous" en JavaScript. Go 1.22 añadió cmp.Or exactamente para eso. Devuelve el primer argumento que no es el valor cero de su tipo:

Trata el valor cero como "ausente", así que no puede distinguir "el puerto es 0 a propósito" de "el puerto no se asignó". Cuando el cero es un valor válido, usa un puntero, un bool aparte o un if explícito.

Una función genérica If, y su trampa

Con genéricos (Go 1.18) puedes escribir una función que parece un ternario:

func If[T any](cond bool, a, b T) T {
	if cond {
		return a
	}
	return b
}

status := If(ok, "pass", "fail")

Funciona con valores sencillos, y algunas bases de código la usan. Pero no es un operador ternario, y la diferencia importa. Go evalúa todos los argumentos antes de llamar a una función, así que tanto a como b se calculan siempre:

La primera llamada calcula tanto "a" como "b", y la segunda provoca un panic por desreferencia de un puntero nil, aunque la condición sea falsa. Un ternario de verdad evaluaría solo el lado elegido. Por tanto:

  • Nunca uses una función así cuando uno de los lados desreferencia un puntero, indexa un slice o lee una entrada de un map que puede no existir.
  • Nunca la uses cuando uno de los lados es caro o tiene efectos secundarios.
  • Para valores baratos y seguros funciona, pero muchos revisores de Go te seguirán pidiendo el if normal.

Puedes hacer perezosas las ramas pasando funciones, If(ok, func() string { return a }, func() string { return b }), pero a esas alturas la sentencia if es más corta.

Otros trucos, y por qué evitarlos

Búsqueda en un map. map[bool]string{true: "yes", false: "no"}[ok] funciona, construye un map y calcula un hash en cada evaluación, y evalúa los dos valores. Es una curiosidad, no un idioma.

Función invocada inmediatamente. Una función anónima llamada en el sitio te da una expresión:

label := func() string {
	if n > 0 {
		return "positive"
	}
	return "non-positive"
}()

Esto sí evalúa de forma perezosa, y a veces ayuda dentro de un literal compuesto donde no cabe una sentencia. La mayoría de las veces, calcular el valor en una variable justo antes del literal es más claro.

Elegir un sustituto

SituaciónUsa
Elegir entre dos valoresvalor por defecto y luego if
Las dos ramas necesitan cálculosif/else
El valor decide el resultado de la funciónreturn temprano
Valor de reserva cuando algo está vacíocmp.Or(value, fallback)
Tres o más casosswitch
Condición repetida con un significadouna pequeña función con nombre

Las propuestas para añadir una expresión condicional aparecen con regularidad en el gestor de issues de Go y hasta ahora se han rechazado. Escribe el if.

Preguntas frecuentes

¿Tiene Go un operador ternario?

No. Go no tiene la expresión cond ? a : b. Las FAQ de Go dicen que los diseñadores lo dejaron fuera porque se usa demasiado a menudo para construir expresiones difíciles de leer. Usa una sentencia if/else.

¿Cómo escribo una asignación condicional en una línea en Go?

Asigna primero el valor por defecto y luego sobrescríbelo:

label := "odd"
if n%2 == 0 {
	label = "even"
}

Ese es el sustituto idiomático. gofmt no pone el cuerpo de un if en una sola línea, así que siempre ocupa al menos tres líneas.

¿Puedo escribir una función ternaria genérica en Go?

Sí: func If[T any](cond bool, a, b T) T { if cond { return a }; return b }. La pega es que Go evalúa todos los argumentos antes de llamar a una función, así que se calculan tanto a como b. If(p != nil, p.Name, "") sigue desreferenciando un p nil y provoca un panic. Un ternario de verdad evaluaría solo un lado.

¿Cómo pongo un valor por defecto si un string está vacío en Go?

Desde Go 1.22, cmp.Or(name, "anonymous") devuelve el primer argumento que no es el valor cero, así que da name salvo que name sea "". Funciona con cualquier tipo comparable y, como cualquier llamada a función, evalúa todos sus argumentos.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR