Jak korzystać z operatora warunkowego (? :) w Ruby?

303

Jak ? :używany jest operator warunkowy ( ) w Ruby?

Na przykład, czy to jest poprawne?

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>
Mithun Sreedharan
źródło
1
tak, myślę, ale myślę też, że można to osiągnąć poprzez: question=question[0,20] Jeśli byłby mniejszy niż 20, nie zmieni tego.
DGM
muszę również dodać „...”, jeśli długość jest większa niż 20
Mithun Sreedharan
1
Uważaj na ślepo, odcinając linię w danej kolumnie. Możesz w końcu wyciąć słowo w połowie, a następnie dodać elipsis („...”), co wygląda źle. Zamiast tego poszukaj pobliskiej interpunkcji lub znaku białych znaków i obetnij tam. Tylko jeśli w pobliżu nie ma lepszego punktu przerwania, należy obciąć słowo w środku.
Tin Man

Odpowiedzi:

496

Jest to operator trójskładnikowy i działa jak w C (nawiasy nie są wymagane). To wyrażenie działa jak:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

Jednak w Ruby ifjest także wyrażenie: if a then b else c end===a ? b : c , z wyjątkiem kwestii pierwszeństwa. Oba są wyrażeniami.

Przykłady:

puts (if 1 then 2 else 3 end) # => 2

puts 1 ? 2 : 3                # => 2

x = if 1 then 2 else 3 end
puts x                        # => 2

Zauważ, że w pierwszym przypadku wymagane są nawiasy (w przeciwnym razie Ruby jest zdezorientowana, ponieważ uważa, że ​​jest puts if 1z dodatkowymi śmieciami), ale w ostatnim przypadku nie są one wymagane, ponieważ wspomniany problem nie pojawia się.

Możesz użyć formularza „long-if” dla czytelności w wielu wierszach:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end
Blaszany Człowiek
źródło
Stawia 0? Wynik 2: 3 daje również 2. Dlaczego?
X_Trust
18
@X_Trust W Ruby jedynymi wartościami fałszowania są nili false. Rzeczywiście niezbyt często.
Kroltan
35
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"
DGM
źródło
Zwięzłe, ale wyjaśnia, co robi.
Tin Man
4
Mała edycja puts (true ? "true" : "false")z nawiasami. W przeciwnym razie kolejność operacji nie jest jasna. Kiedy po raz pierwszy to przeczytałem, byłem zdezorientowany, ponieważ czytałem to, ponieważ (puts true) ? "true" : "false"spodziewałem putssię zwrócić wartość logiczną, która następnie stała się wartością ciągu.
Fresheyeball
26

Twoje użycie ERB sugeruje, że jesteś w Railsach. Jeśli tak, to weź pod uwagę truncatewbudowanego pomocnika, który wykona za Ciebie zadanie:

<% question = truncate(question, :length=>30) %>
Wayne Conrad
źródło
To jest świetne! co dokładnie chcę zrobić !!
Mithun Sreedharan
11
Jest już późno, ale byłem pod wrażeniem tej odpowiedzi, która przeskoczyła wszystkie aspekty składniowe i od razu poszła do tego, co pytający próbował osiągnąć.
Mike Buckbee
2
+1, ale erb niekoniecznie oznacza szyny (Sinatra, samodzielny ERB itp.).
Fox Wilson,
17

@pst dał świetną odpowiedź, ale chciałbym wspomnieć, że w Ruby operator trójskładnikowy jest napisany w jednym wierszu, aby był poprawny pod względem składniowym, w przeciwieństwie do Perla i C, gdzie możemy napisać go w wielu wierszach:

(true) ? 1 : 0

Normalnie Ruby zgłosi błąd, jeśli spróbujesz podzielić go na wiele linii, ale możesz użyć \symbolu kontynuacji linii na końcu linii, a Ruby będzie szczęśliwa:

(true)   \
  ? 1    \
  : 0

Jest to prosty przykład, ale może być bardzo przydatny w przypadku dłuższych linii, ponieważ utrzymuje ładnie ułożony kod.

Możliwe jest również użycie trójki bez znaków kontynuacji linii poprzez umieszczenie operatorów na końcu linii, ale mi się to nie podoba lub nie polecam:

(true) ?
  1 :
  0

Myślę, że prowadzi to do naprawdę trudnego do odczytania kodu, ponieważ test warunkowy i / lub wyniki stają się dłuższe.

Czytałem komentarze mówiące, aby nie używać operatora trójskładnikowego, ponieważ jest to mylące, ale to zły powód, aby czegoś nie używać. Zgodnie z tą samą logiką nie powinniśmy używać wyrażeń regularnych, operatorów zakresów („ ..” i pozornie nieznanej odmiany „flip-flop”). Są potężne, gdy są właściwie używane, dlatego powinniśmy nauczyć się ich poprawnie używać.


Dlaczego wstawiłeś nawiasy true?

Rozważ przykład PO:

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>

Zawijanie testu warunkowego pomaga uczynić go bardziej czytelnym, ponieważ wizualnie oddziela test:

<% question = (question.size > 20) ? question.question.slice(0, 20)+"..." : question.question %>

Oczywiście cały przykład można uczynić o wiele bardziej czytelnym, stosując rozsądne dodatki do białych znaków. To nie zostało przetestowane, ale wpadniesz na pomysł:

<% question = (question.size > 20) ? question.question.slice(0, 20) + "..." \
                                   : question.question 
%>

Lub, bardziej napisane bardziej idiomatycznie:

<% question = if (question.size > 20)
                question.question.slice(0, 20) + "..."
              else 
                question.question 
              end
%>

Łatwo byłoby argumentować, że czytelność również bardzo ucierpiała question.question.

Blaszany Człowiek
źródło
1
Jeśli korzystasz z wielu linii, dlaczego nie użyć, jeśli ... jeszcze ... koniec?
Wayne Conrad
1
Z powodu zbyt wielu lat pracy w Perlu i C? Używam albo, w zależności od sytuacji i tego, czy jedno jest wizualnie wyraźniejsze od drugiego. Czasami, jeśli / else jest zbyt gadatliwy, czasem?: Jest brzydki.
Tin Man
1
@WayneConrad If ma co najmniej jeden problem wyjaśniony w tej odpowiedzi: stackoverflow.com/a/4252945/2597260 Porównaj kilka sposobów korzystania z multiline operatora if / ternary: gist.github.com/nedzadarek/0f9f99755d42bad10c30
Darek Nędza
Dlaczego wstawiłeś nawiasy true?
Zac
1
Ponieważ truetak naprawdę zasiada za czymś, co byłoby wyrażeniem, które ocenia na truelub false. Lepiej oddzielić je wizualnie, ponieważ potrójne stwierdzenia mogą szybko przekształcić się w szum wizualny, zmniejszając czytelność, co wpływa na łatwość konserwacji.
Tin Man
3

Prosty przykład, w którym operator sprawdza, czy identyfikator gracza wynosi 1, i ustawia identyfikator wroga w zależności od wyniku

player_id=1
....
player_id==1? enemy_id=2 : enemy_id=1
# => enemy=2

I znalazłem post na ten temat, który wydaje się bardzo pomocny.

devwanderer
źródło
4
Dlaczego nie enemy_id = player_id == 1 ? 2 : 1?
Aaron Blenkush,
1
@AaronBlenkush Dzięki za elegancki wkład. Nadal jestem na poziomie nooba, prawdopodobnie dlatego :)
devwanderer
0

Kod condition ? statement_A : statement_Bjest równoważny z

if condition == true
  statement_A
else
  statement_B
end
Umesh Malhotra
źródło
0

Najprostszy sposób:

param_a = 1
param_b = 2

result = param_a === param_b ? 'Same!' : 'Not same!'

ponieważ param_anie jest równa, param_bwówczas resultwartość będzieNot same!

Adrian Eranzi
źródło