Bạn có thể biết rằng Ruby gắn các đối số dòng lệnh vào một mảng toàn cục được gọi là ARGV. Nhưng tại sao nó lại được gọi là ARGV? Đó là một bài học lịch sử thú vị làm nổi bật nguồn gốc của Ruby ở C.
Vectơ đối số
ARGV là viết tắt của vector đối số. Và "vector" trong cách sử dụng lâu đời kỳ lạ này có nghĩa là "mảng một chiều".
Trong C, mọi chương trình đều có main()
hàm số. Nó thường trông giống như sau:
int main(int argc, char *argv[]) {
... your code here
}
Như bạn có thể nhận thấy, hàm main có hai đối số. Đây tương ứng là một số đếm và một mảng các đối số dòng lệnh.
Khi bạn yêu cầu bash chạy chương trình của mình, nó sẽ thực hiện một lệnh gọi hệ thống khiến hệ điều hành gọi main
của chương trình của bạn và để chuyển vào một số argc
và argv
các giá trị.
Hồng ngọc
Trình thông dịch Ruby - ít nhất là MRI - chỉ là một chương trình C. Đây là main
của Ruby chức năng:
int
main(int argc, char **argv)
{
#ifdef RUBY_DEBUG_ENV
ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
setlocale(LC_CTYPE, "");
#endif
ruby_sysinit(&argc, &argv);
{
RUBY_INIT_STACK;
ruby_init();
return ruby_run_node(ruby_options(argc, argv));
}
}
Như bạn thấy, nó vượt qua argc
và argv
vào một hàm có tên là ruby_options
, lần lượt gọi ruby_process_options
, gọi process_options
.
Điều đó xử lý tất cả các tùy chọn trình thông dịch ruby và cuối cùng gọi ruby_set_argv
, đặt ARGV
bạn thấy trong mã ruby của bạn.
void
ruby_set_argv(int argc, char **argv)
{
int i;
VALUE av = rb_argv;
#if defined(USE_DLN_A_OUT)
if (origarg.argv)
dln_argv0 = origarg.argv[0];
else
dln_argv0 = argv[0];
#endif
rb_ary_clear(av);
for (i = 0; i < argc; i++) {
VALUE arg = external_str_new_cstr(argv[i]);
OBJ_FREEZE(arg);
rb_ary_push(av, arg);
}
}
Khá gọn gàng. Tôi vẫn còn rất mới trong việc tìm hiểu về cơ sở mã MRI, nhưng thật thú vị khi nhảy vào và xem chính xác cách mọi thứ hoạt động.