범위의 이야기
11515 단어 Ruby
내부적으로 어려운 말을 할 수 없기 때문에 문서를 바탕으로 뭔가를 쓰면 좋겠다고 생각했는데 마침 루비의 버전 업그레이드에서 Range를 사용하는 처리 행위가 바뀌는 상황을 만났고 이를 계기로 단말기가 없고 시작이 없는 Range를 조사했습니다.나는 그 일을 쓰고 싶다.
개요
Ruby2.6에서 끝 없음까지, Ruby2.7에서 끝 없음까지 사용할 수 있습니다.
각 버전에서 생성된 시작과 끝이 없는 범위가 재미있기 때문에 소개해 드리겠습니다.
끝 없음 및 끝 없음
1.. # 終端なし
..10 # 始端なし
시작도 끝도 생략할 수 없다... # syntax error
그러나 시작 단말기는 없는 범위를 쓸 수 있다.nil..nil
터미널이나 시작이nil일 때의 버전별 차이
이 버전의 실행 결과는 다음과 같다.1..nil
# < 2.6: ArgumentError
# >= 2.6: 1..
nil..10
# < 2.7: ArgumentError
# >= 2.7: ..10
nil..nil
# < 2.6: nil..nil
# ~> 2.6: nil..
# >= 2.7: nil..nil
처음의 두 가지 차이는 뚜렷하지만 마지막 것은 아직 이해하기 어렵다.
< 2.6: nil..nil
이것은 nil
부터 nil
까지의 범위이다.
크기는 nil
, 포함 nil
뿐입니다.range = nil..nil
range.size #=> nil
range.cover?(nil) #=> true
~> 2.6: nil..
이것도 nil
부터 시작된 단말기 없는 범위다.
여기의 사이즈도 nil
, nil
만 포함됩니다.range = nil..nil
range.size #=> nil
range.cover?(nil) #=> true
>= 2.7: nil..nil
마지막으로 여기는 처음에 말한 바와 같이 시단 단말기도 없는 범위이다.
크기는 Infinity
의 모든 내용을 포함합니다.range = nil..nil
range.size #=> Infinity
range.cover?(nil) #=> true
range.cover?(1) #=> true
range.cover?('s') #=> true
range.cover?(true) #=> true
그나저나 마지막nil..nil
은sizeInfinity
이기 때문에nil..
과..nil
상황에서의size도 소개했지만 Range#size
과는Array#size
다른것으로단순히요소의개수를나타내는 것이 아니다.('a'..'z').size #=> nil
('a'..'z').to_a.size #=> 26
원소수를 나타내는 방법이지만 말단 시작단이 모두 Numeric
인 자류 대상이나 nil
을 제외하고는 nil
로 되돌아간다.
범위 변경 불가
루비의 범위 클래스는immutable입니다.대상 자체를 파괴적으로 변경해서는 안 된다는 것이다.따라서 한 번에 생성된 범위의 대상이 가리키는 범위는 절대 변경할 수 없습니다.
이렇게 말하면 파괴적인 변경을 할 방법을 강구한다.
...하지만 많은 조사를 했지만 파괴적인 변경 수단은 없었다.
이별에 즈음하여 증언하다.
Range#begin
과Range#first
,Range#end
과Range#last
는 같은 설명으로 쓰여 있지만 시작이 없거나 단말기가 없는 경우 결과는 다르다.
Range#begin (..10).begin #=> nil
(..10).first #=> RangeError
Range#end (1..).end #=> nil
(1..).last #=> RangeError
소스 코드를 읽어보면 설치가 좀 다른 것 같아요.# Range#begin
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
# Range#first
static VALUE
range_first(int argc, VALUE *argv, VALUE range)
{
VALUE n, ary[2];
if (NIL_P(RANGE_BEG(range))) {
rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
}
if (argc == 0) return RANGE_BEG(range);
rb_scan_args(argc, argv, "1", &n);
ary[0] = n;
ary[1] = rb_ary_new2(NUM2LONG(n));
rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
return ary[1];
}
C언어는 전혀 알아볼 수 없지만 언뜻 보면 Range#first
과Range#last
과begin
에서 얻은 값이 end
인 경우 예외가 발생한다.
이후nil
와Range#first
매개 변수를 전달하면 최초와 마지막을 기점으로 여러 개의 값을 얻을 수 있기 때문에 이 부분의 처리인 것 같습니다.
이 부근의 동작의 차이를 잘 설명할 수 있는 글을 생각해 내면 수정 PR을 작성한다.
참고로 여기의'edit'링크를 통해 PR을 만들 수 있습니다.
Range#last
반환Range#size
의 경우도 있고, 단말기나 시단이 Numeric
하위 클래스 대상이 아니라면, nil
단말기1..nil
는 nil
하위 클래스 대상이 아니지만, Numeric
반환nil
은 아니다.여기의 해석이 어떤지 모르기 때문에일 단순히 틀렸다고 할 수는 없지만 이해하기 쉬운 표현변경의 여지가 있는 것 같습니다.
Range#size
총결산
평소에 자주 사용하는 클래스의 대상도 문서를 다시 읽으면서 옆에서 이동하면 새로운 발견을 할 수 있어 즐겁다.
처음에 설명한 "Ruby 버전 업그레이드에서 Range를 사용한 처리 행위가 변경된 사태"에 대한 코드는 다음과 같습니다.(time_or_nil..).cover?(time)
Time 객체의 값을 위의 끝 없음 범위Infinity
와 비교하고 포함될 경우 반환합니다===
.Range는 때때로 true
형식을 취하는데 이런 경우에는 반드시 nil..
되돌아오지만 여기서 2.7로 올라갈 때는 반드시 되돌아온다 false
.같은 상황을 겪는 사람이 있을지도 모르니 주의하세요.
개인이라면 괜찮지만 일이면 다른 사람이 쓴 코드를 파악하지 못하기 때문에 이런 버전 업그레이드는 행동을 바꾸는 부분을 특히 쉽게 볼 수 있다.행동이 변할 때 주울 수 있도록 평소에 시험을 잘 쓰고 싶어요.
참고 자료
활차 true
의 값(1..nil).end
이 단말기로 인식될 수 있는지 여부.여기nil
는'단말기 없음'을 표시하기 때문에 단말기도 nil
가 아니라'무'라고 할 수 있다. ↩
Reference
이 문제에 관하여(범위의 이야기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/rhiroe/items/5ef77da3e8767723aad2
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
1.. # 終端なし
..10 # 始端なし
.. # syntax error
nil..nil
1..nil
# < 2.6: ArgumentError
# >= 2.6: 1..
nil..10
# < 2.7: ArgumentError
# >= 2.7: ..10
nil..nil
# < 2.6: nil..nil
# ~> 2.6: nil..
# >= 2.7: nil..nil
range = nil..nil
range.size #=> nil
range.cover?(nil) #=> true
range = nil..nil
range.size #=> nil
range.cover?(nil) #=> true
range = nil..nil
range.size #=> Infinity
range.cover?(nil) #=> true
range.cover?(1) #=> true
range.cover?('s') #=> true
range.cover?(true) #=> true
('a'..'z').size #=> nil
('a'..'z').to_a.size #=> 26
(..10).begin #=> nil
(..10).first #=> RangeError
(1..).end #=> nil
(1..).last #=> RangeError
# Range#begin
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
# Range#first
static VALUE
range_first(int argc, VALUE *argv, VALUE range)
{
VALUE n, ary[2];
if (NIL_P(RANGE_BEG(range))) {
rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
}
if (argc == 0) return RANGE_BEG(range);
rb_scan_args(argc, argv, "1", &n);
ary[0] = n;
ary[1] = rb_ary_new2(NUM2LONG(n));
rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
return ary[1];
}
평소에 자주 사용하는 클래스의 대상도 문서를 다시 읽으면서 옆에서 이동하면 새로운 발견을 할 수 있어 즐겁다.
처음에 설명한 "Ruby 버전 업그레이드에서 Range를 사용한 처리 행위가 변경된 사태"에 대한 코드는 다음과 같습니다.
(time_or_nil..).cover?(time)
Time 객체의 값을 위의 끝 없음 범위Infinity
와 비교하고 포함될 경우 반환합니다===
.Range는 때때로 true
형식을 취하는데 이런 경우에는 반드시 nil..
되돌아오지만 여기서 2.7로 올라갈 때는 반드시 되돌아온다 false
.같은 상황을 겪는 사람이 있을지도 모르니 주의하세요.개인이라면 괜찮지만 일이면 다른 사람이 쓴 코드를 파악하지 못하기 때문에 이런 버전 업그레이드는 행동을 바꾸는 부분을 특히 쉽게 볼 수 있다.행동이 변할 때 주울 수 있도록 평소에 시험을 잘 쓰고 싶어요.
참고 자료
활차 true
의 값(1..nil).end
이 단말기로 인식될 수 있는지 여부.여기nil
는'단말기 없음'을 표시하기 때문에 단말기도 nil
가 아니라'무'라고 할 수 있다. ↩
Reference
이 문제에 관하여(범위의 이야기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/rhiroe/items/5ef77da3e8767723aad2
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(범위의 이야기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/rhiroe/items/5ef77da3e8767723aad2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)