go - operador ternario en c ejemplos
¿Cuál es el equivalente idiomático del operador ternario de C? (8)
En C / C ++ (y en muchos idiomas de esa familia), una expresión común para declarar e inicializar una variable en función de una condición utiliza el operador condicional ternario:
int index = val > 0 ? val : -val
Go no tiene el operador condicional. ¿Cuál es la forma más idiomática de implementar el mismo código de arriba? Llegué a la siguiente solución, pero parece bastante prolija
var index int
if val > 0 {
index = val
} else {
index = -val
}
¿Hay algo mejor?
Como se señaló (y afortunadamente, como era de esperar), usar if+else
es de hecho la forma idiomática de hacer condicionales en Go.
Además del bloque de códigos var+if+else
completamente volado, esta ortografía también se usa a menudo:
index := val
if val <= 0 {
index = -val
}
y si tiene un bloque de código que es lo suficientemente repetitivo, como el equivalente de int value = a <= b ? a : b
int value = a <= b ? a : b
, puede crear una función para mantenerlo:
func min(a, b int) int {
if a <= b {
return a
}
return b
}
...
value := min(a, b)
El compilador alineará funciones tan simples, por lo que es rápido, más claro y más corto.
El mapa ternario es fácil de leer sin paréntesis:
c := map[bool]int{true: 1, false: 0} [5 > 4]
La respuesta de eold es interesante y creativa, tal vez incluso inteligente.
Sin embargo, se recomienda hacer:
var index int
if val > 0 {
index = printPositiveAndReturn(val)
} else {
index = slowlyReturn(-val) // or slowlyNegate(val)
}
Sí, ambos compilan hasta esencialmente el mismo ensamblado, sin embargo, este código es mucho más legible que llamar a una función anónima solo para devolver un valor que podría haberse escrito en la variable en primer lugar.
Básicamente, el código simple y claro es mejor que el código creativo.
Además, cualquier código que use un literal de mapa no es una buena idea, porque los mapas no son livianos en Go. Desde Go 1.3, se garantiza el orden de iteración aleatorio para mapas pequeños, y para hacer cumplir esto, se ha vuelto un poco menos eficiente en cuanto a la memoria para mapas pequeños.
Como resultado, crear y eliminar numerosos mapas pequeños consume mucho espacio y consume mucho tiempo. Tenía un código que usaba un pequeño mapa (dos o tres teclas, probablemente, pero el caso de uso común era solo una entrada). Pero el código era demasiado lento. Estamos hablando de al menos 3 órdenes de magnitud más lento que el mismo código reescrito para usar un mapa de [índice] de doble división => mapa [índice] de datos. Y probablemente fue más. Como algunas operaciones que anteriormente tardaban unos minutos en ejecutarse, comenzaron a completarse en milisegundos.
No Go no tiene un operador ternario, el uso de la sintaxis if / else es la forma idiomática: http://golang.org/doc/faq#Does_Go_have_a_ternary_form
Si todas sus sucursales producen efectos secundarios o son computacionalmente caras, lo siguiente sería una refactorización semánticamente preservada :
index := func() int {
if val > 0 {
return printPositiveAndReturn(val)
} else {
return slowlyReturn(-val) // or slowlyNegate(val)
}
}(); # exactly one branch will be evaluated
normalmente sin sobrecarga (en línea) y, lo que es más importante, sin saturar su espacio de nombres con funciones de ayuda que solo se usan una vez (lo que dificulta la legibilidad y el mantenimiento). Ejemplo en vivo
Tenga en cuenta si debe aplicar ingenuamente el enfoque de Gustavo :
index := printPositiveAndReturn(val);
if val <= 0 {
index = slowlyReturn(-val); // or slowlyNegate(val)
}
obtendrías un programa con un comportamiento diferente ; en caso de que val <= 0
programa imprima un valor no positivo mientras que no debería! (Análogamente, si invirtieras las ramas, introducirías sobrecarga llamando a una función lenta innecesariamente).
Supongamos que tiene la siguiente expresión ternaria (en C):
int a = test ? 1 : 2;
El enfoque idiomático en Go sería simplemente usar un bloque if
:
var a int
if test {
a = 1
} else {
a = 2
}
Sin embargo, eso podría no ajustarse a sus requisitos. En mi caso, necesitaba una expresión en línea para una plantilla de generación de código.
Utilicé una función anónima evaluada inmediatamente:
a := func() int { if test { return 1 } else { return 2 } }()
Esto asegura que ambas ramas no sean evaluadas también.
/*
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
val := (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + carry
func Ternary(statement bool, a, b interface{}) interface{} {
if statement {
return a
}
return b
}
func Abs(n int) int {
return Ternary(n >= 0, n, -n).(int)
}
Esto no superará if / else y requiere conversión, pero funciona. FYI:
BenchmarkAbsTernary-8 100000000 18.8 ns / op
BenchmarkAbsIfElse-8 2000000000 0.27 ns / op