¿Cuál es el equivalente idiomático del operador ternario de C?

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 comstackdor alineará funciones tan simples, por lo que es rápido, más claro y más corto.

No Go no tiene un operador ternario, el uso de la syntax if / else es la forma idiomática: http://golang.org/doc/faq#Does_Go_have_a_ternary_form

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 twigs no sean evaluadas también.

El mapa ternario es fácil de leer sin paréntesis:

 c := map[bool]int{true: 1, false: 0} [5 > 4] 
 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

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 progtwig con un comportamiento diferente ; en caso de que val < = 0 progtwig imprima un valor no positivo mientras que no debería! (Análogamente, si invirtieras las twigs, introducirías sobrecarga llamando a una función lenta innecesariamente).

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 comstackn 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.

 /* * type ListNode struct { * Val int * Next *ListNode * } */ val := (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + carry