2010-01-01 9 views
7

estoy usando la gema authlogic con Ruby on Rails, y he estado usando el siguiente para obtener el ID del usuario que ha iniciado la sesión en:signo doble en Ruby

current_user = UserSession.find 
id = current_user && current_user.record.id 

No estoy entendiendo cómo current_user & & current_user.record.id devuelve la identificación de usuario actual. Yo pensaría que esto devolvería un booleano. ¿Alguien puede explicar cómo funciona esto?

Respuesta

8

Lo lógico es el cortocircuito. Eso significa que si el constructo es X & & Y, y X es falso, Y nunca se verifica porque todo va a ser falso.

Ese código está diciendo, en esencia:

if (current_user is TRUE) { 
    id = current_user.record.id; 
] 

aquí hay algo de salida de la consola que muestra a obtener el segundo valor si la primera es verdadera:

irb(main):005:0> true && 9 
=> 9 

y nil si la primera es nula:

irb(main):008:0> nil && 9 
=> nil 
+0

Interesante.En PHP y en algunos otros lenguajes, a menudo uso booleanValue = booleanExpression1 && booleanExpression2 y, en función de la evaluación de la expresión "y", booleanValue se configurará correctamente. ¿Entonces esto no es posible con Ruby? –

+0

PHP y otros C-me gusta cortocircuitan sus && s también. Cuando usa booleanos, los resultados son los que espera, pero cuando tiene tipos de objetos y tipos dinámicos, se encuentra en la zona específica del idioma. –

+0

Además, si X (current_user) es falso (supongo que esto significa que current_user no está configurado - nil?), ¿Id se establecerá en falso en lugar de int (el valor de current_user.record.id)? –

18

No hay Boolean tipo en Ruby; Ruby tiene una visión bastante simple de la verdad (o más precisamente, tiene una visión bastante simple de falsedad).

  • el objeto false, que es la instancia singleton de FalseClass se considera Falsy
  • el objeto nil, que es la instancia singleton de NilClass es Falsy
  • todos los demás objetos es truthy (incluido, obviamente, el objeto true, que es la instancia única de TrueClass)

[Por cierto: esto significa que una gran cantidad de objetos que se consideran Falsy en algunos otros idiomas, son en realidad Truthy en Ruby, al igual que el número entero 0, el valor real 0.0, la cadena vacía, la matriz vacía, el hash vacío, el carácter 'F']

Por lo tanto, los operadores booleanos &&, ||, and y orno devuelven valores booleanos. En su lugar, devuelven el primer objeto que determina el resultado de la expresión.

(También provocan un cortocircuito, lo que significa que solo evalúan las subexpresiones mínimas necesarias para determinar el resultado de la expresión. Por lo tanto, una formulación alternativa sería que devuelvan el resultado de la última expresión eso fue evaluado. Lo cual, a su vez, es análogo a lo que hacen los bloques, métodos, cuerpos de clase y cuerpos de módulos.)

Entonces, ¿qué significa decir para devolver el primer objeto que determina el resultado? Eso es simple, realmente: el resultado de la expresión

a && b 

es Truthy si tantoa y b son Truthy, de lo contrario, es Falsy. Por lo tanto, si a es Falsy, es completamente irrelevante lo b es: el resultado será Falsy de cualquier manera. Por lo tanto, podríamos simplemente devolver a. (Recuerde que una no tiene que ser false, que también podría ser nil y el programador puede querer saber cuál de los dos era.)

Si, otoh, a es Truthy (OIA es ni nil ni false), a continuación, el resultado de toda la expresión es exclusivamente dependiente en b: si b es Truthy, todo el resultado será Truthy, de lo contrario si b es Falsy, todo el resultado será falsy. Por lo tanto, también podríamos devolver b, en lugar de convertirlo primero en un booleano.

|| y or son análogos o más precisamente dual-&& y and.

el que has publicado este ejemplo: no

id = current_user && current_user.record.id 

Aquí, el autor es aún esperando current_user ser un valor booleano! En cambio, espera que sea User o nil. Pero eso está perfectamente bien, porque un User es truthy y nil es falsy, por lo que aún se pueden usar en una expresión booleana.

La intención básica es que el autor desea evitar que se produzca una excepción NoMethodError, si intenta llamar al #record en nil.

Una forma alternativa de expresar esto sería

id = current_user.record.id unless current_user.nil? 

Si desea que todos los detalles morbosos, echa un vistazo a la sección 11.1 (página 36) de los Draft ISO Ruby Specification o las especificaciones del excutable RubySpec project. (Here's the one for &&.)

Escribí pure Ruby implementation of Ruby's Boolean operators and conditional expressions una vez por diversión. La carne de las implementaciones es estos twomixins.

+0

esto podría ser una entrada de blog :) – Dty

+1

@Dty: It * is *. Simplemente no tengo un blog ;-) –

+0

örg: ¿te importa si te pregunto a qué te dedicas si no eres un "programador"? ¡Parece que sabes mucho de un programador "recreativo"! PD. Ojalá hubiera una forma de enviar mensajes instantáneos en SO. – Dty

Cuestiones relacionadas