Giới thiệu
Tôi rất yêu thích ngôn ngữ lập trình Crystal. Trong hai hoặc ba năm qua, tôi đã xây dựng nhiều công cụ dòng lệnh (CLI) bằng Crystal. Trong suốt thời gian này, tôi thường so sánh nó với Ruby và đã gặp nhiều khác biệt, khám phá và thử thách. Trong bài viết này, tôi sẽ chia sẻ những điều mà tôi đã học được.
1. Sự Tương Đồng với Ruby
Crystal trông rất giống với Ruby. Nhiều biểu thức phổ biến trong Ruby cũng hoạt động trong Crystal. Crystal là ngôn ngữ kiểu tĩnh, nhưng hầu hết thời gian bạn không cần viết kiểu một cách rõ ràng. Trình suy diễn kiểu sẽ thực hiện công việc đó cho bạn.
2. Sử Dụng DeepWiki
DeepWiki là một nguồn tài nguyên rất hữu ích để học Crystal. Đối với một ngôn ngữ ít người biết, nó là một trong những nguồn tốt nhất. Bạn thậm chí có thể đặt câu hỏi bằng ngôn ngữ mẹ đẻ của mình.
3. Mảng và Bảng Băm Không Thể Trộn Kiểu
Trong Crystal, bạn không thể tự do trộn các kiểu khác nhau trong một Array
hoặc Hash
. Ruby cho phép điều này, nhưng Crystal thì không. Bạn có thể sử dụng kiểu liên hợp, nhưng thường thì tốt hơn là tránh chúng. Thay vào đó, hãy xem xét một trong số các tùy chọn sau:
- Tạo một lớp hoặc cấu trúc
- Sử dụng một bản ghi
- Sử dụng một Tuple cho dữ liệu tạm thời
Ban đầu, điều này có thể cảm thấy bất tiện, nhưng bạn sẽ quen với nó.
crystal
# Mảng(Int32 | String | Symbol) - không được khuyến nghị
arr = [1, "hai", :ba]
# OK: Liên hợp được viết rõ ràng
arr : Array(Int32 | String | Symbol) = [1, "hai", :ba]
# OK: Tuple cho vị trí cố định
t = {1, "hai", :ba}
# OK: bản ghi cho dữ liệu có cấu trúc
record Item, id : Int32, name : String, tag : Symbol
items = [
Item.new(1, "táo", :trái_cây),
Item.new(2, "cam", :trái_cây),
]
4. Không Có eval
Crystal không có eval
. Đây là một sự khác biệt lớn so với Ruby. Nếu bạn thực sự cần đánh giá động, bạn nên sử dụng Ruby. Một lựa chọn khác là nhúng mruby hoặc sử dụng một thư viện như Anyolite. Crystal có một trình thông dịch, nhưng nó không thực tế và chậm hơn Ruby hoặc mruby.
ruby
# Ruby
code = "1 + 2"
puts eval(code) # => 3
crystal
# Crystal không có eval
# Bạn phải thiết kế khác đi
5. Nạp Phương Thức
Trong Ruby, việc phân nhánh dựa trên kiểu tham số trong một phương thức là điều phổ biến. Trong Crystal, việc sử dụng nạp phương thức là tự nhiên hơn. Điều này làm cho mã rõ ràng hơn.
crystal
def square(x : Int32) : Int32
x * x
end
def square(x : String) : Int32
square(x.to_i)
end
puts square(12) # => 144
puts square("12") # => 144
6. Kiểu Trả Về Cần Phải Nhất Quán
Trong Ruby, một phương thức có thể trả về các giá trị của các kiểu khác nhau. Trong Crystal, nếu kiểu trả về không rõ ràng, bạn sẽ gặp rắc rối. Nếu bạn muốn trả về nhiều kiểu khác nhau, bạn nên tách phương thức. Bạn có thể sử dụng một kiểu liên hợp, nhưng không được khuyến nghị.
crystal
# không được khuyến nghị
def maybe_value(flag : Bool) : Int32 | String
flag ? 42 : "bốn mươi hai"
end
crystal
def value_int : Int32
42
end
def value_str : String
"bốn mươi hai"
end
7. Xử Lý Nil
Chú ý xem biến có thể là Nil
hay không. Nếu có, bạn cần xử lý nó với not_nil!
, if val = maybe_val
, hoặc toán tử điều hướng an toàn.
crystal
name : String? = nil
if n = name
puts n.upcase
else
raise "tên là nil"
end
8. Thu Gom Rác
Crystal sử dụng LLVM và dựa vào một GC bên ngoài (libgc
). Hiệu suất thường gần giống với Rust hoặc Nim, nhưng việc phân tích và điều chỉnh bộ nhớ có thể khó khăn. Hơn nữa, thời gian của GC không thể dự đoán được, vì vậy Crystal có thể không phù hợp cho các hệ thống thời gian thực.
9. I/O Không Đồng Bộ
I/O không đồng bộ có sẵn theo mặc định. Một số lập trình viên cảm thấy nó dễ sử dụng hơn so với Rust.
10. Liên Kết Khi Phân Phối
Các chương trình Crystal thường được liên kết với libgc
và các thư viện khác như libpcre2
. Hãy cẩn thận khi phân phối nhị phân.
- Linux: Bạn có thể xây dựng các nhị phân liên kết tĩnh với GitHub Actions + Docker + musl
- macOS: Bạn có thể chuẩn bị một Homebrew Tap, hoặc xây dựng các nhị phân di động với liên kết tĩnh cho
libgc
,libpcre2
, và các thư viện khác
Xem thêm: workflow của GitHub actions trong lolcat.cr
11. Hỗ Trợ Windows
Crystal giờ đây hoạt động trên Windows (MSVC / MinGW64) ổn định hơn trước. Thực thi song song cũng hoạt động. Tuy nhiên, việc giải quyết các phụ thuộc thư viện C vẫn có thể gặp khó khăn. Nếu bạn không quen thuộc với Windows, bạn có thể cần hỏi AI để được trợ giúp.
12. Hạn Chế của OptionParser
OptionParser
chuẩn không hỗ trợ các tùy chọn ngắn kết hợp. Vì vậy ls -l -h
hoạt động, nhưng ls -lh
thì không. Tôi dự định tạo một pull request để sửa điều này trong tương lai.
Kết Luận
Viết các công cụ dòng lệnh bằng Crystal đôi khi rất đau đầu. Nhưng đồng thời, bạn học được rất nhiều. Tôi tin rằng "những ngày tốt nhất" của ngôn ngữ Crystal không phải ở quá khứ hay hiện tại, mà ở tương lai.
Bài viết này ban đầu dựa trên phản hồi của tôi trong một chủ đề trên Reddit, sau đó mở rộng thành một bài viết tiếng Nhật trên Qiita, và giờ được dịch sang tiếng Việt với sự trợ giúp của ChatGPT.
- Cân nhắc viết lại công cụ CLI của tôi từ Ruby sang Crystal - tôi nên chú ý đến điều gì?
- Crystalでコマンドラインツールを作って気づいた12のこと