대부분은 _
IRB에서 마지막 반환 값에 대한 홀더로서 ‘의 특별한 의미를 알고 있지만, 이것이 제가 여기서 묻는 것이 아닙니다 .
대신 _
평범한 루비 코드에서 변수 이름으로 사용되는 경우 에 대해 묻습니다 . 여기서는 “Do n’t care 변수”(à la Prolog ) 와 유사한 특별한 동작이있는 것으로 보입니다 . 다음은 고유 한 동작을 보여주는 몇 가지 유용한 예입니다.
lambda { |x, x| 42 } # SyntaxError: duplicated argument name
lambda { |_, _| 42 }.call(4, 2) # => 42
lambda { |_, _| 42 }.call(_, _) # NameError: undefined local variable or method `_'
lambda { |_| _ + 1 }.call(42) # => 43
lambda { |_, _| _ }.call(4, 2) # 1.8.7: => 2
# 1.9.3: => 4
_ = 42
_ * 100 # => 4200
_, _ = 4, 2; _ # => 2
이들은 모두 puts
추가 기능과의 충돌을 피하기 위해 IRB가 아닌 Ruby에서 직접 실행되었습니다 (가 추가 된 상태).
이 행동에 대한 문서를 어디서도 찾을 수 없기 때문에 이것은 모두 내 실험의 결과입니다 (분명히 검색하기 가장 쉬운 것은 아닙니다). 궁극적으로이 모든 것이 내부적으로 어떻게 작동하는지 궁금해서 .NET의 특별한 점을 정확히 이해할 수 있습니다 _
. 그래서 문서에 대한 참조를 요청하고, 바람직하게는 Ruby 에서 동작 하는 방식을 보여주는 Ruby 소스 코드 (및 아마도 RubySpec )를 요청합니다 _
.
답변
“중복 인수 이름”오류를 억제하기 위해 소스에 몇 가지 특수 처리가 있습니다. 에 나타납니다에만 오류 메시지 shadowing_lvar_gen
내부 parse.y
, 이 같은 1.9.3 버전 외모 :
static ID
shadowing_lvar_gen(struct parser_params *parser, ID name)
{
if (idUScore == name) return name;
/* ... */
그리고 idUScore
됩니다 에 정의 된id.c
이 같은 :
REGISTER_SYMID(idUScore, "_");
에서 유사한 특수 처리를 볼 수 있습니다 warn_unused_var
.
static void
warn_unused_var(struct parser_params *parser, struct local_vars *local)
{
/* ... */
for (i = 0; i < cnt; ++i) {
if (!v[i] || (u[i] & LVAR_USED)) continue;
if (idUScore == v[i]) continue;
rb_compile_warn(ruby_sourcefile, (int)u[i], "assigned but unused variable - %s", rb_id2name(v[i]));
}
}
for
루프 의 두 번째 줄에서 경고가 표시되지 않음을 알 수 있습니다.
_
1.9.3 소스에서 찾을 수있는 유일한 특수 처리 는 위의 것입니다. 중복 이름 오류가 억제되고 사용되지 않는 변수 경고가 억제됩니다. 이 두 가지 외에는 다른 것과 _
마찬가지로 평범한 오래된 변수입니다. .NET의 (사소한) 특수성에 대한 문서를 모릅니다 _
.
Ruby 2.0에서 idUScore == v[i]
테스트 warn_unused_var
는 다음과 같은 호출로 대체되었습니다 is_private_local_id
.
if (is_private_local_id(v[i])) continue;
rb_warn4S(ruby_sourcefile, (int)u[i], "assigned but unused variable - %s", rb_id2name(v[i]));
다음으로 is_private_local_id
시작하는 변수에 대한 경고를 억제합니다 _
.
if (name == idUScore) return 1;
/* ... */
return RSTRING_PTR(s)[0] == '_';
_
그 자체 보다는 . 2.0은 상황을 약간 느슨하게합니다.
답변
_
유효한 식별자입니다. 식별자는 밑줄을 포함 할 수있을뿐만 아니라 밑줄이 될 수도 있습니다 .
_ = o = Object.new
_.object_id == o.object_id
# => true
메서드 이름으로 사용할 수도 있습니다.
def o._; :_ end
o._
# => :_
물론, 정확히 읽을 수있는 이름은 아니며, 변수가 참조하는 내용이나 메서드가 수행하는 작업에 대한 정보를 독자에게 전달하지 않습니다.
IRB
특히, _
마지막 표현식의 값으로 설정 됩니다.
$ irb
> 'asd'
# => "asd"
> _
# => "asd"
그대로 소스 코드에서 , 단순히 설정 _
마지막 값 :
@workspace.evaluate self, "_ = IRB.CurrentContext.last_value"
일부 저장소를 탐색했습니다. 내가 찾은 내용은 다음과 같습니다.
파일의 마지막 줄 id.c
에는 다음과 같은 호출이 있습니다.
REGISTER_SYMID(idUScore, "_");
grep
에 대한 소스를 사용하면 idUScore
두 가지 관련성있는 결과를 얻었습니다.
shadowing_lvar_gen
블록의 형식 매개 변수가 다른 범위에 존재하는 동일한 이름의 변수를 대체하는 메커니즘 인 것 같습니다. “중복 된 인자 이름” SyntaxError
과 “섀도 잉 외부 지역 변수”경고를 발생 시키는 것으로 보이는 함수입니다 .
에 grep
대한 소스를 검색 한 후 Ruby 1.9.3의 변경 로그shadowing_lvar_gen
에서 다음 을 발견했습니다 .
2007 년 12 월 11 일 화요일 01:21:21 마츠모토 유키히로
- parse.y (shadowing_lvar_gen) : “_”에 대한 중복 오류가 없습니다.
이 줄 의 원점 일 가능성이 높은 :
if (idUScore == name) return name;
이것으로부터 나는 같은 상황 proc { |_, _| :x }.call :a, :b
에서 한 _
변수가 다른 변수를 단순히 그림자 로 만든다고 추론합니다 .
문제의 커밋은 다음과 같습니다 . 기본적으로 다음 두 줄을 도입했습니다.
if (!uscore) uscore = rb_intern("_");
if (uscore == name) return;
idUScore
분명히 존재조차하지 않았던 시대부터 .