[크리스탈과 ○○] 크리스탈과 특수 변수
크리스탈은 수치를 보존하는 프레임워크로 로컬 변수, 실례 변수, 클래스 변수와 상수를 활용할 수 있으며, 이번에는 컴파일러가 따로 준비한 특수 변수를 소개한다.
$로 시작하는 특수 변수
루비에서
$
로 시작하는 변수 이름은 글로벌 변수이지만 크리스탈에는 글로벌 범위의 변수가 없습니다.크리스탈은 이를 특수 변수(Special Variables)라고 부른다.특수 변수는 특정 트리거(외부 명령을 실행하거나 정규 표현식과 일치)에 따라 값을 설정하는 변수로 트리거가 방법 내에서 발생할 때 수치를 참조할 수 있는 것은 방법 내에만 한정되며 특수 변수의 작용 범위는 로컬 변수와 매우 비슷하다.
Crystal에는 C라이브러리의 바인딩 정의
$
에 사용된 것과 비슷한 다른 변수lib
로 시작하는 변수가 있습니다.C 라이브러리의 변수는 라이브러리 이름과 유사한 클래스 방법의 접근기가 있지만 변수 자체는 전역 역할 영역이 없기 때문에 라이브러리 밖에서 변수 이름으로 직접 접근할 수 없습니다.
lib Lib
$var : Int32
end
Lib.var = 1
Lib.var #=> 1
$?
최상위 정의
system()
방법이나 `
방법 등을 사용하여 외부 명령을 실행할 때 이 명령의 종료 상태는 Process:Status형으로 저장됩니다.파일이 있는 ls 명령 실행 지정하기
`ls exist_file`
$? #=> <Process::Status:0x103f7fc60 @exit_status=0>
존재하지 않는 파일의 ls 명령 실행 지정하기`ls non_exist_file`
$? #=> <Process::Status:0x103f7fb20 @exit_status=256>
$?.exit_status == 0
또는 $?.success?
에서 이전의 명령이 정상적으로 끝났는지 판별할 수 있다.외부 명령을 실행하지 않은 상태
$?
에서는 예외(NilAssiertionError)가 발생합니다.외부 명령을 한 번도 실행하지 않았다면
$?
#=> Unhandled exception: Nil assertion failed (NilAssertionError)
$~
선 정규 표현식 일치 결과는 Regex:MatchData 형식으로 저장됩니다.
"abcde" =~ /cd/
#=> 2
$~
#=> Regex::MatchData("cd")
정규 표현식이 없거나 이전에 정규 표현식이 일치하지 않아 객체 문자열이 일치하지 않으면 참조$~
에 예외(NilAssiertionError)가 발생합니다.일치하지 않을 때
"abcde" =~ /ef/
#=> nil
$~
#=> Unhandled exception: Nil assertion failed (NilAssertionError)
$정수
이전의 정규 표현식 매칭에서 정규 표현식 모델이 포획조
()
의 일부분을 가지고 있다면 매칭에 성공하면 n번째 포획 결과는 변수$n
로 인용할 수 있다."abcde" =~ /a(.+)d/
$1
#=> "bc"
$~
와 마찬가지로 정규 표현식이 실행되지 않았거나 이전에 정규 표현식이 일치하지 않아 대상 문자열이 일치하지 않으면 예외(NilAssiertionError)가 발생합니다.일치하지 않을 때
"abcde" =~ /a(.+)f/
$1
#=> Unhandled exception: Nil assertion failed (NilAssertionError)
또한 n 이 캡처 그룹 수보다 크도록 지정하면 IndexError 가 발생합니다.존재하지 않는 포획 그룹을 지정할 때
"abcde" =~ /a(.+)d/
$2
#=> Unhandled exception: Invalid capture group index: 2 (IndexError)
__ 에 포함된 특수 변수
대문자의 따옴표 상자 앞뒤에
__
로 묶인 특수 변수(Ruby는 위조 변수라고 부른다)에는 다음과 같은 4가지 유형이 존재한다.__FILE__
__DIR__
__LINE__
__END_LINE__
그러나
__FILE__
와__DIR__
등 사용 장면은 상대적이다. __LINE__
와__END_LINE__
라면 크리스탈의 코드 자체를 처리 대상으로 하는 특수한 예를 제외하고는 사용 장면이 상당히 제한된 것 같다.__FILE__
설명
__FILE__
의 원본 파일의 전체 경로가 문자열에 저장됩니다.파일의 상대 경로를 사용하여 프로젝트 디렉토리에 있는 다른 파일을 지정할 때 매우 편리합니다.
/path/file.cr
__FILE__
#=> "/path/file.cr"
방법 매개 변수의 기본값으로 사용할 때, 기술__FILE__
의 파일이 아니라 기술 방법이 호출된 파일 경로를 저장합니다./path/file_method.cr
def file_path(path = __FILE__)
path
end
/path/file_caller.crrequire "./file_method.cr"
file_path
#=> "/path/file_caller.cr"
# __FILE__ は file_method.cr 内に記述されているが、呼び出し側の file_caller.cr が返る
Rubby의 경우 실행 중인 스크립트 파일$0
을 삽입 변수if $0 == __FILE__ ...
에 저장하는 느낌에서 이 파일을 루비 명령의 매개 변수로 직접 전달할 때 실행하는 처리를 기술합니다.크리스탈은 $0
에 해당하는 기능이 없다. (적어도 나는 찾지 못했다.)삽입식 상수
PROGRAM_NAME
는 실행 프로그램의 전체 경로를 저장하지만 원본 파일 이름이 아니라 실행 파일 이름이기 때문에 __FILE__
와 비교할 수 없습니다.__DIR__
사용한 원본 파일을 배치하는 디렉터리의 전체 경로가 문자열에 저장됩니다.
File.dirname(__FILE__)
에 해당하며 사용 장면도 크게 달라지지 않았다./tmp/dir.cr
__DIR__ #=> "/tmp"
방법 매개 변수의 기본값으로 사용할 때 저장된 파일은 __DIR__
기술된 파일이 아니라 방법이 호출된 파일이 놓인 디렉터리 경로를 기록합니다./path/sub/dir_method.cr
def dir_path(path = __DIR__)
path
end
/path/dir_caller.crrequire "./sub/__dir__method.cr"
dir_path
#=> "/path"
# __DIR__ は /path/sub 内のファイルに記述されているが、呼び出し側のファイルがある /path が返る
__LINE__
인용할 때의 줄 번호는 정수 값으로 저장됩니다.
/path/line.cr
__LINE__
#=> 1
__LINE__
#=> 3
방법 매개 변수의 기본값으로 사용할 때 기술__LINE__
의 줄이 아니라 방법이 호출된 줄 수를 참조한다./path/line2.cr
def __line__(line = __LINE__)
line
end
__line__
#=> 5
# __LINE__ が記述された1行目ではなく、呼び出し側の5行目が返る
__END_LINE__
__END_LINE__
는 __
부터 시작된 변수 중 특별한 변수로 일반적으로 참고하면 오류가 발생할 수 있습니다.__END_LINE__
#=> Error: __END_LINE__ can only be used in default argument value
오류 메시지와 같이 이 __END_LINE__
는 메소드 매개 변수의 기본값으로만 사용할 수 있습니다.메소드 매개 변수의 기본값
__END_LINE__
을 지정하면 메소드가 호출한 마지막 행의 행 수를 저장합니다.예를 들어 방법의 호출이 1행으로 끝날 때 상기
__LINE__
와 같은 행위를 취한다./path/end_line.cr
def foo(end_line = __END_LINE__)
end_line
end
foo
#=> 5
다른 한편, 방법이 여러 줄을 뛰어넘으면 마지막 줄의 줄 수를 저장한다./path/end_line2.cr
def foo(a, b, c, end_line = __END_LINE__)
end_line
end
foo("arg a",
"arg b",
"arg c") # <- この行
#=> 7
또한 블록이 있는 메서드가 있는 매개변수에서 사용되는 경우 __END_LINE__
에는 블록이 정의한 마지막 행의 행 수가 저장됩니다./path/end_line3.cr
def foo(end_line = __END_LINE__, &block)
yield end_line
end
foo do |end_line|
bar #=> 7
end # <- この行
즉, 방법에 대해 __FILE__
,__LINE__
,__END_LINE__
를 각각 기본값의 매개 변수로 정의하면 방법은 이 방법이 호출한 기술이 어느 파일의 몇 줄에서 몇 줄로 기술되었는지 식별할 수 있다./path/location.cr
def location(path = __FILE__, line = __LINE__, end_line = __END_LINE__)
yield "#{path} #{line}:#{end_line}"
end
/path/location_caller.crrequire "./location.cr"
location do |loc|
loc #=> "/path/location_callsr.cr 3:5"
end
☠️ 특수 변수 대입
특수 변수는 기본적으로 컴파일러가 지정한 값으로 사용자는 자신의 코드에 값을 대입할 생각을 하지 않는다.
어떤 특수 변수는 상황에 따라 수치를 대입할 수 있지만 이것은 이후에 오류가 발생한 원인이므로 원칙적으로 이런 변수를 대입해서는 안 된다.
특수 변수가 오류를 일으키는 예
def foo
$? = 1
end
foo
`ls`
출력Module validation failed: Call parameter type does not match function signature!
%"$?" = alloca %"(Int32 | Process::Status | Nil)", !dbg !9
%"(Int32 | Nil)"* %58 = call i32 @"*foo:Int32"(%"(Int32 | Process::Status | Nil)"* %"$?"), !dbg !81
Call parameter type does not match function signature!
%"$?" = alloca %"(Int32 | Process::Status | Nil)", !dbg !9
%"Process::Status"** %59 = call %String* @"*`<String>:String"(%String* bitcast ({ i32, i32, i32, [3 x i8] }* @"'ls'" to %String*), %"(Int32 | Process::Status | Nil)"* %"$?"), !dbg !82
(Exception)
from raise<Exception>:NoReturn
from raise<String>:NoReturn
from Crystal::CodeGenVisitor#finish:Nil
from Crystal::Compiler#codegen<Crystal::Program, Crystal::ASTNode+, Array(Crystal::Compiler::Source), String>:(Tuple(Array(Crystal::Compiler::CompilationUnit), Array(String)) | Nil)
from Crystal::Compiler#compile<Array(Crystal::Compiler::Source), String>:Crystal::Compiler::Result
from Crystal::Command#run_command<Bool>:Nil
from Crystal::Command#run:(Bool | Nil)
from __crystal_main
from main
Error: you've found a bug in the Crystal compiler. Please open an issue, including source code that will allow us to reproduce the bug: https://github.com/crystal-lang/crystal/issues
이번 총결산
유
$
시작 또는 __
에 포함된 특수 변수Reference
이 문제에 관하여([크리스탈과 ○○] 크리스탈과 특수 변수), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/arcage/articles/crystal_and_special_variables텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)