[크리스탈과 ○○] 크리스탈과 특수 변수

15958 단어 Crystaltech
📖 [크리스탈과 ○○] 내용 일람
크리스탈은 수치를 보존하는 프레임워크로 로컬 변수, 실례 변수, 클래스 변수와 상수를 활용할 수 있으며, 이번에는 컴파일러가 따로 준비한 특수 변수를 소개한다.

$로 시작하는 특수 변수


루비에서 $로 시작하는 변수 이름은 글로벌 변수이지만 크리스탈에는 글로벌 범위의 변수가 없습니다.크리스탈은 이를 특수 변수(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.cr
    require "./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.cr
    require "./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.cr
    require "./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
    

    이번 총결산


  • $시작 또는 __에 포함된 특수 변수
  • 그것들은 컴파일러가 준비한 것으로 원칙적으로 사용자 설정값을 예상하지 않는다
  • 좋은 웹페이지 즐겨찾기