루비에서 || = (또는 같음)은 무엇을 의미합니까?


340

루비에서 다음 코드는 무엇을 의미합니까?

||=

구문에 대한 의미 나 이유가 있습니까?

답변:


175

이 질문은 루비 메일 링리스트와 루비 블로그에서 자주 논의되었는데, 이제 루비 메일 링리스트에이 문제를 논의하는 루비 메일 링리스트 의 다른 모든 스레드 에 대한 링크를 수집하는 것이 유일한 목적인 스레드도 있습니다. .

하나는 다음과 같습니다. || = (또는 동일한) 스레드 및 페이지의 최종 목록

당신이 경우 정말 무슨 일이 일어나고 있는지 알고 싶어의 "단축 할당"섹션 11.4.2.3 한 번 봐 걸릴 루비 언어 초안 사양 .

첫 번째 근사치로

a ||= b

에 해당

a || a = b

하지 에 해당

a = a || b

그러나 특히 a정의되지 않은 경우 첫 번째 근사치 입니다. 시맨틱은 단순 변수 할당, 메소드 할당 또는 인덱싱 할당인지에 따라 다릅니다.

a    ||= b
a.c  ||= b
a[c] ||= b

모두 다르게 취급됩니다.


2
두 번째 링크는 비트 로트 ( stackoverflow.com/users/540162/nightfirecat에 의한 메타 주석)로 인해 어려움을 겪었습니다 .
Andrew Grimm

331
그것은 매우 비밀스럽고 답이 아닙니다. 짧은 대답은 다음과 같습니다. a || = b는 a가 정의되지 않은 경우 b 값을 할당하고 그렇지 않으면 그대로 둡니다. (좋아, 거기에 뉘앙스 특별한 경우가 있지만, 그 기본 경우입니다.)
스티브 베넷

20
@SteveBennett : 나는 당신의 대답이 "뉘앙스"라고 말하는 것을 a = false; a ||= true하지 않는 사실을 부르지 않을 것입니다.
Jörg W Mittag

23
사람들이 계속해서이 질문에 대해 여러 번 질문했기 때문에이 질문이 여러 번 요청되었을 수 있습니다.
einnocent

8
이 답변을 통해 왜 여러 스레드가 있는지 쉽게 알 수 있습니다. 초보자 모자를 사용하여이 질문에 대한 답변을 검색하려고하면 모든 답변이 명확하지 않은 것을 알 수 있습니다. 예를 들어, 이것으로 당신은 아닌 것을 말하고 있습니다. 나는 대답을 향상시키고 초보자에게 쉬운 답변을 제공하는 것이 좋습니다 : a = b
한가

594

a ||= bA는 조건 할당 연산자 . 이 수단 경우 a미정되거나 falsey 후 평가 b및 집합 a결과로 . 마찬가지로 a정의되고 진실로 b평가되면 평가되지 않으며 할당이 수행되지 않습니다. 예를 들면 다음과 같습니다.

a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0

foo = false # => false
foo ||= true # => true
foo ||= false # => true

혼란스럽게도 다른 할당 연산자 (예 :)와 비슷 +=하지만 다르게 동작합니다.

  • a += b 로 번역 a = a + b
  • a ||= b 대략적으로 a || a = b

의 속기입니다 a || a = b. 차이는 때이다 a정의되지 a || a = b올리는 것 NameError반면, a ||= b세트 ab. 이 구별은 경우 중요하지 않습니다 ab로컬 변수가 있지만 하나가 클래스의 게터 / setter 메소드의 경우 중요합니다.

더 읽을 거리 :


52
이 답변에 감사드립니다.
Tom Hert

충분히 검색하지 않았지만 여전히 a = a || 대신 이것을 사용하는 이유를 얻지 못합니다. 비. 어쩌면 내 개인적인 의견이지만 그런 뉘앙스가 존재한다는 약간 말도
안될 것입니다

2
@dtc, 고려하십시오 h = Hash.new(0); h[1] ||= 2. 이제 두 가지 가능한 확장 h[1] = h[1] || 2대를 고려하십시오 h[1] || h[1] = 2. 두 표현식 모두 평가 0되지만 첫 번째 표현식 은 해시 크기를 불필요하게 증가시킵니다. 아마도 이것이 Matz가 ||=두 번째 확장과 같은 행동 을하도록 선택한 이유 일 것입니다 . (나는 이것을 다른 답변에 연결된 스레드 중 하나의 예를 기반으로했습니다.)
antinome

1
루피를 배우는 사람에게는 이것이 우리가 필요로하는 답변의 유형입니다. 우리가 || =의 의미를 알았다면 아마도 그 질문은 다르게 표현되었을 것입니다.
OBCENEIKON

1
참고로, a || a = b제기 NameError하는 경우 a정의되지 않습니다. a ||= b하지 않고 대신 초기화 a하고로 설정합니다 b. 그것이 내가 아는 한이 둘의 유일한 차이점입니다. 마찬가지로, 사이의 유일한 차이점 a = a || ba ||= b제가 알고 그 경우이다 a=방법, 그것은 관계없이 어떤 전화를받을 것이다 a돌아갑니다. 또한, 사이의 유일한 차이점 a = b unless aa ||= b제가 알고 그에게 그 문을 평가하는 것입니다 nil대신 a하는 경우가 atruthy입니다. 근사치가 많지만 그에 상응하는 것은 없습니다.
Ajedi32

32

간결하고 완전한 답변

a ||= b

다음 줄과 동일한 방식으로 평가

a || a = b
a ? a : a = b
if a then a else a = b end

-

반면에

a = a || b

다음 줄과 동일한 방식으로 평가

a = a ? a : b
if a then a = a else a = b end

-

편집 : AJedi32가 주석에서 지적했듯이 다음과 같은 경우에만 적용됩니다. 1. a는 정의 된 변수입니다. 2. 한 번 및 두 번 평가해도 프로그램 또는 시스템 상태에는 차이가 없습니다.


1
확실한가요? 이는 afalse / zero / undefined 인 경우 두 번 평가됨을 의미합니다 . (그러나 나는 루비를 모른다. 그래서 lvalues가 정확하게 '평가'될 수 있는지 모르겠다 ...)
Steve Bennett

당신이 무슨 말을하는지 봅니다. 두 줄이 동등하다는 의미는 전체 줄이 평가 된 후 종료 상태가 동일하다는 것입니다. 이는 a, b의 값과 반환되는 것을 의미합니다. 루비 인터프리터가 여러 상태를 평가하기 위해 여러 상태를 사용하는지 여부는 전적으로 가능합니다. 루비 통역 전문가가 있습니까?
the_minted

3
이것은 옳지 않습니다. a || a = b, a ? a : a = b, if a then a else a = b endif a then a = a else a = b end경우에 오류가 발생한다 a정의되어있는 반면 a ||= ba = a || b하지 않습니다. 또한, a || a = b, a ? a : a = b, if a then a else a = b end, a = a ? a : b, 및 if a then a = a else a = b end평가 a두 번 때 atruthy이며, 반면 a ||= ba = a || b하지 않습니다.
Ajedi32

1
* 수정 : 참이면 두 번 a || a = b평가되지 않습니다 . aa
Ajedi32

1
@the_minted 반드시 the end state will be equivalent after the whole line has been evaluated그런 것은 아닙니다. a방법이 무엇입니까 ? 방법은 부작용이있을 수 있습니다. 예로는 public; def a=n; @a=n; end; def a; @a+=1; end; self.a = 5, self.a ||= b6을 반환하지만 self.a ? self.a : self.a = b7을 반환합니다
Ajedi32

27

짧은에서 a||=b수단 : 만약이 a있다 undefined, nil or false, 할당 ba. 그렇지 않으면 a그대로 유지하십시오.


16
원래,


x ||= y 방법

경우 x모든 값을 갖고, 그렇지 않으면 설정, 혼자 떠나 값을 변경하지 않습니다 xy


13

또는 같음을 의미합니다. 왼쪽의 값이 정의되어 있는지 확인한 다음 사용하십시오. 그렇지 않은 경우 오른쪽의 값을 사용하십시오. Rails에서이를 사용하여 모델에서 인스턴스 변수를 캐시 할 수 있습니다.

현재 로그인 한 사용자를 가져 오는 함수를 생성하는 빠른 Rails 기반 예제 :

class User > ActiveRecord::Base

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end

end

@current_user 인스턴스 변수가 설정되어 있는지 확인합니다. 있는 경우이를 리턴하여 데이터베이스 호출을 저장합니다. 그러나 설정되어 있지 않으면 호출 한 다음 @current_user 변수를 설정합니다. 실제로 간단한 캐싱 기술이지만 응용 프로그램에서 동일한 인스턴스 변수를 여러 번 가져올 때 유용합니다.


8
이것은 잘못이다. Ruby-Forum.Com/topic/151660 및 여기에 제공된 링크를 읽으 십시오 .
Jörg W Mittag

1
@ Jo (umlaut) rg, 나는 그것에 대해 무엇이 잘못되었는지 알지 못합니다. 귀하의 링크는 다른 링크의 목록입니다. 왜 그것이 잘못되었는지에 대한 실제적인 설명은 없습니다. 단지 당신의 가치 판단처럼 들립니다.
eggmatters

이 답변은 트리거뿐만 아니라 때문에, 잘못 undefined뿐만 아니라에, false그리고 nil관련이되지 않을 수도있는, current_user그러나 특히이 false다른 경우 unexpectecd 수 있습니다
dfherr

이 답변에 불완전한 내용이 있지만 (nil / false에서는 작동하지 않음) || =를 사용하려는 이유를 설명하는 첫 번째 질문이므로 감사합니다!
Jonathan Tuzman


8

정확하게 말하면, a ||= b" a정의되지 않거나 허위 ( false또는 nil) 인 경우,로 설정 a하여 b평가 (즉, 반환)로 b, 그렇지 않으면 a"로 평가합니다 .

다른 사람들은 종종 그 말함으로써이 문제를 설명하기 위해 시도 a ||= b에 해당 a || a = b하거나 a = a || b. 이러한 동등성은 개념을 이해하는 데 도움이 될 수 있지만 모든 조건에서 정확 하지는 않습니다 . 설명해주세요 :

  • a ||= ba || a = b ?

    이 명령문의 동작은 a정의되지 않은 로컬 변수 인 경우와 다릅니다 . 이 경우으로 a ||= b설정 a하고 b(으로 평가 b) 반면 a || a = b을 올리십시오 NameError: undefined local variable or method 'a' for main:Object.

  • a ||= ba = a || b ?

    이러한 진술의 동등성은 종종 유사한 등가 다른 마찬가지입니다 때문에, 가정 단축 할당 사업자 (즉 +=, -=, *=, /=, %=, **=, &=, |=, ^=, <<=, 및 >>=). 그러나 ||=이러한 진술의 행동은 대상에 대한 방법 이며 진실 할 때 다를 수 있습니다 . 이 경우, (에 평가 이외의 아무것도 할 것입니다 반면,) 호출 에 의 수신기를. 다른 사람들 이 지적했듯이, 이것은 호출 에 해시에 키를 추가하는 것과 같은 부작용이 있을 때 차이를 만들 수 있습니다 .a=aa ||= baa = a || ba=(a)aa=a

  • a ||= ba = b unless a ??

    이 진술의 행동은 그들이 a진실한 때에 평가하는 것만 다릅니다 . 이 경우에는 a = b unless a로 평가 nil되지만 ( a예상대로 설정되지는 않지만 )로 a ||= b평가됩니다 a.

  • a ||= bdefined?(a) ? (a || a = b) : (a = b) ????

    아직도 아니야. 이 문은에 method_missing대한 값을 반환하는 메서드가 있을 때 다를 수 있습니다 a. 이 경우, a ||= b어떤으로 평가합니다 method_missing반환하고, 세트에 시도하지 a반면, defined?(a) ? (a || a = b) : (a = b)설정됩니다 ab와로 평가 b.

좋아, 좋아, 그럼 입니다 a ||= b 동등? 루비로 이것을 표현하는 방법이 있습니까?

글쎄, 내가 아무것도 간과하지 않는다고 가정하면, a ||= b기능적으로는 ... ( drumroll )

begin
  a = nil if false
  a || a = b
end

기다려! noop가있는 첫 번째 예가 아닌가? 글쎄요 내가 전에 말한 방법 이 정의되지 않은 지역 변수 인 경우 a ||= b와 같지 않다는 것을 기억 합니까? 글쎄, 그 행이 실행되지 않더라도 정의되지 않은 것을 보장합니다 . Ruby의 지역 변수는 어휘 범위가 있습니다.a || a = baa = nil if falsea


확장 된 세 번째 예 :(a=b unless a) or a
vol7ron

1
@ vol7ron # 2와 비슷한 문제가 있습니다. 경우 a방법은, 그것은 대신 (그것이 truthy 값을 처음 반환하는 경우)를 한 번으로 두 번 호출됩니다. 예를 들어 a돌아 오는 데 시간이 오래 걸리거나 부작용이있는 경우 동작이 달라질 수 있습니다 .
Ajedi32

또한, 첫 번째 문장은 말을 안 할당 ba 좌변은 여전히 RHS에 그 값을 설정하지 않습니다, 우변은 여전히 좌에 할당하지 않거나, 다른 말로하면?
vol7ron

a ||= b인터넷에서 찾은 최고의 답변입니다. 감사.
Eric Duminil 2016 년

3

unless x x = y end

x에 값이 없거나 (nil 또는 false가 아닌 경우) y와 동일하게 설정하십시오.

에 해당

x ||= y


3

가정 a = 2하고b = 3

그런 다음 a ||= b 에 결과 것 a즉,의 값 2.

어떤 값으로 평가하여하지에했을 때와 같은 false또는 nil그 왜 .. 그의 ll평가하지 b의 값입니다.

이제 a = nil및을 가정하십시오 b = 3.

그런 다음 a ||= b에 결과 것 3즉, b의 값입니다.

처음으로 결과를 평가하려고 시도한 결과 nil..b .

ror 앱에서 사용되는 가장 좋은 예는 다음과 같습니다.

#To get currently logged in iser
def current_user
  @current_user ||= User.find_by_id(session[:user_id])
end

# Make current_user available in templates as a helper
helper_method :current_user

어디서 초기화되지 않은 User.find_by_id(session[:user_id])경우에만 실행됩니다 @current_user.


3

a || = b

'a'에 값이 존재하고 해당 값을 사용하여 유지를 변경하지 않으려는 경우를 나타냅니다. 그렇지 않으면 'a'에 값이 없으면 'b'의 값을 사용하십시오.

왼쪽이 null이 아닌 경우 간단한 단어는 기존 값을 가리키고, 그렇지 않으면 오른쪽의 값을 가리 킵니다.


2
a ||= b

에 해당

a || a = b

그리고 아닙니다

a = a || b

기본값으로 해시를 정의하는 상황으로 인해 (해시는 정의되지 않은 키의 기본값을 반환합니다)

a = Hash.new(true) #Which is: {}

사용하는 경우 :

a[10] ||= 10 #same as a[10] || a[10] = 10

는 여전히 :

{}

그러나 당신이 그렇게 쓸 때 :

a[10] = a[10] || 10

a가된다 :

{10 => true}

key에 자체 값을 할당했기 때문에 10기본값은 true이므로 이제 10할당을 절대 수행하지 않고 키에 대해 해시가 정의 됩니다.


2

게으른 인스턴스화와 같습니다. 변수가 이미 정의되어 있으면 값을 다시 작성하는 대신 해당 값을 사용합니다.


2

또한 ||=원자 연산이 아니므로 스레드 안전하지 않습니다. 경험상 클래스 메소드에는 사용하지 마십시오.


2

이것이 기본 할당 표기법입니다

예를 들어 : x || = 1
x가 nil인지 아닌지를 확인합니다. x가 실제로 nil이면 새로운 값을 할당합니다 (이 예에서는 1).

더 명시 적 인
경우 : x == nil
x = 1
end


하나 nil또는 false뿐만 아니라nil
알렉스 Poca

2

|| =조건부 할당 연산자입니다

  x ||= y

에 해당

  x = x || y

또는 대안 적으로

if defined?(x) and x
    x = x
else 
    x = y
end

2

X값이 없으면 값이 할당됩니다 Y. 그렇지 않으면이 예제에서는 원래 값인 5를 유지합니다.

irb(main):020:0> x = 5
=> 5
irb(main):021:0> y = 10
=> 10
irb(main):022:0> x ||= y
=> 5

# Now set x to nil. 

irb(main):025:0> x = nil
=> nil
irb(main):026:0> x ||= y
=> 10

1

일반적인 오해로, a ||= b일치하지 않는 a = a || b,하지만처럼 동작합니다 a || a = b.

그러나 여기 까다로운 경우가 있습니다. 경우 a, 정의되지 않은 a || a = 42인상을 NameError하면서 a ||= 42돌아갑니다 42. 따라서 그들은 동등한 표현이 아닌 것 같습니다.


1

||= left == nil (또는 undefined 또는 false) 인 경우에만 오른쪽에 값을 할당합니다.


당신은 아마 오른쪽 대신 '왼쪽에 값 할당'을 의미했을 것입니다
Maysam Torabi


0
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1

a이미 설정되어 있기 때문에1

irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2

때문에 a 이었다nil


여기에 답변 날짜는 무엇입니까? 왜 연도를 표시하지 않습니까?
Shiv

0
b = 5
a ||= b

이것은 다음과 같이 번역됩니다.

a = a || b

어느 것

a = nil || 5

그래서 마침내

a = 5

이제 다시 전화하면 :

a ||= b
a = a || b
a = 5 || 5
a = 5

b = 6

이제 다시 전화하면 :

a ||= b
a = a || b
a = 5 || 6
a = 5 

관찰하면 b값이에 할당되지 않습니다 a. a여전히 가질 것이다5 .

루비에서 접근 자의 속도를 높이기 위해 사용되는 메모 패턴입니다.

def users
  @users ||= User.all
end

이것은 기본적으로 다음과 같이 번역됩니다.

@users = @users || User.all

따라서이 메소드를 처음 호출 할 때 데이터베이스를 호출하게됩니다.

이 방법에 대한 미래의 호출은의 값이 반환됩니다 @users인스턴스 변수를.


0

||= 조건부 할당 연산자라고합니다.

기본적으로 작동 =하지만 변수 가 이미 할당 된 경우 아무것도하지 않는 것을 제외하고는 작동합니다 .

첫 번째 예 :

x ||= 10

두 번째 예 :

x = 20
x ||= 10

첫 번째 예 x에서는 이제 10과 같습니다. 그러나 두 번째 예 x에서는 이미 20으로 정의되어 있습니다. 따라서 조건부 연산자는 적용되지 않습니다. x실행 후 여전히 20 x ||= 10입니다.


-2

a ||= b말과 동일 a = b if a.nil?또는a = b unless a

그러나 세 가지 옵션 모두 동일한 성능을 보여줍니까? Ruby 2.5.1에서는

1000000.times do
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
end

PC에서 0.099 초 소요

1000000.times do
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
end

0.062 초가 걸립니다. 거의 40 % 빠릅니다.

그리고 우리는 또한 :

1000000.times do
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
end

0.166 초가 걸립니다.

이것이 일반적인 성능에 큰 영향을 미치지는 않지만 마지막 최적화가 필요한 경우이 결과를 고려하십시오. 그건 그렇고 : a = 1 unless a초보자가 읽기 쉽기 때문에 설명이 필요 없습니다.

참고 1 : 할당 라인을 여러 번 반복하는 이유는 측정 된 시간에 루프의 오버 헤드를 줄이는 것입니다.

참고 2 : a=nil할당 전에 nil을 입력 하면 결과가 비슷 합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.