if statement - multiple - ¿Por qué la instrucción switch y no if-else?
switch in c# sample (8)
Me he estado preguntando esto desde hace un tiempo. No soy un programador hardcore, principalmente pequeños scripts de Python y he escrito un par de simulaciones de dinámica molecular. Para la pregunta real: ¿Cuál es el punto de la declaración de cambio ? ¿Por qué no puedes usar la instrucción if-else ?
Gracias por su respuesta y si esto se ha preguntado antes, apúnteme al enlace.
EDITAR
S.Lott ha señalado que esto puede ser un duplicado de las preguntas If / Else vs. Switch . Si quiere cerrar, hágalo. Lo dejaré abierto para mayor discusión.
Además de la otra legibilidad y optimización de código mencionadas en .NET, también tienes la posibilidad de encender enumeraciones, etc.
enum Color { Red, Green, Blue };
Color c = Color.Red;
switch (c) // Switch on the enum
{
// no casting and no need to understand what int value it is
case Color.Red: break;
case Color.Green: break;
case Color.Blue: break;
}
En cuanto a la expresividad, la instrucción switch / case le permite agrupar múltiples casos, por ejemplo:
case 1,2,3: do(this); break;
case 4,5,6: do(that); break;
Para el rendimiento, los compiladores a veces pueden optimizar las sentencias de cambio en tablas de salto.
Estoy ignorando este tipo de optimización de bajo nivel ya que generalmente no es importante, y probablemente sea diferente del compilador al compilador.
Yo diría que la principal diferencia es la legibilidad. if / else es muy flexible, pero cuando ves un cambio sabes de inmediato que todas las pruebas están en contra de la misma expresión.
La capacidad de pasar por varios casos (omitir intencionalmente la declaración de interrupción) puede ser útil, y como algunas personas ya han dicho, es más rápido también. Tal vez la consideración más importante y menos importante, sin embargo, es que solo hace que el código sea más lindo que if / else. :)
Los únicos interruptores de tiempo pueden ser más rápidos cuando los valores de su caso son constantes, no dinámicos o derivados de otra manera, y cuando el número de casos es significativamente mayor que el tiempo para calcular un hash en una tabla de búsqueda.
Un ejemplo para Javascript, que se compila para ensamblar para su ejecución en la mayoría de los motores, incluido el motor V8 de Chrome, es que las sentencias de conmutación son un 30% -60% más lentas de ejecutar en el caso común: http://jsperf.com/switch-if-else/20
Switch puede ser optimizado como "Mejor" por algunos compiladores. Hay trampas con el uso de la declaración de cambio en ciertos idiomas. En Java, el conmutador no puede manejar cadenas y en VB2005 la instrucción de conmutación no funcionará con botones de opción.
Switch puede ser más rápido y fácil de leer, If-Then es más genérico y funcionará en más lugares.
Switch se puede optimizar compilando r: obtendrá un código más rápido.
También me parece más elegante cuando se trata de tipos enumerables.
Para resumir, la declaración del interruptor te ofrece un rendimiento + código de elegancia :)
Aquí hay algunos enlaces útiles:
- comparación de velocidad de cambio vs if / else en C #
- Optimización de la declaración del conmutador guiado por la retroalimentación (pdf que describe la optimización de la declaración del conmutador)
Una construcción de interruptor se traduce más fácilmente en una tabla de salto (o rama) . Esto puede hacer que las sentencias switch sean mucho más eficientes que if-else cuando las etiquetas case están muy juntas. La idea es colocar un montón de instrucciones de salto secuencialmente en la memoria y luego agregar el valor al contador del programa. Esto reemplaza una secuencia de instrucciones de comparación con una operación de agregar.
A continuación se encuentran algunos ejemplos de ensamblaje de psuedo extremadamente simplificados. Primero, la versión if-else:
// C version
if (1 == value)
function1();
else if (2 == value)
function2();
else if (3 == value)
function3();
// assembly version
compare value, 1
jump if zero label1
compare value, 2
jump if zero label2
compare value, 3
jump if zero label3
label1:
call function1
label2:
call function2
label3:
call function3
El siguiente es la versión del interruptor:
// C version
switch (value) {
case 1: function1(); break;
case 2: function2(); break;
case 3: function3(); break;
}
// assembly version
add program_counter, value
call function1
call function2
call function3
Puede ver que el código ensamblador resultante es mucho más compacto. Tenga en cuenta que el valor tendría que transformarse de alguna manera para manejar otros valores distintos de 1, 2 y 3. Sin embargo, esto debería ilustrar el concepto.