
Rust-ის გაკვეთილი: რატომ ჯობია მონაცემების შემოწმებას მათი ტიპად გადაქცევა
Eli Bendersky-მ ახალი ესე გამოაქვეყნა Alexis King-ის 2019 წლის იდეაზე: მონაცემები არა მხოლოდ უნდა შემოწმდეს, არამედ ისეთ ტიპად უნდა გადაიქცეს, რომ დადასტურებული თვისების დარღვევა შეუძლებელი გახდეს.
Eli Bendersky-მ საკუთარ ბლოგზე ახალი ესე გამოაქვეყნა, რომელიც Alexis King-ის 2019 წლის სტატიის იდეას უბრუნდება. King-ის ტექსტი Haskell-ისთვის დაიწერა და ამტკიცებს, რომ კოდმა მონაცემი არა მხოლოდ უნდა შეამოწმოს და შემდეგ ენდოს, არამედ ისეთ ტიპად გარდაქმნას, რომლისთვისაც დადასტურებული თვისების დარღვევა შეუძლებელია. Bendersky იმავე მიდგომას Rust-ზე ამოწმებს და მაგალითებს ენის სტანდარტულ ბიბლიოთეკასა და ცნობილ პროექტებში ეძებს.
ვექტორი, რომელიც ცარიელი ვერ იქნება
საწყისი წერტილი ჩვეულებრივი Vec და მისი first() მეთოდია, რომელიც არასავალდებულო მითითებას აბრუნებს, ვინაიდან ვექტორს შესაძლოა ერთი ელემენტიც არ ჰქონდეს. Bendersky-ის მაგალითში ფუნქცია CONFIG_DIRS-იდან კონფიგურაციის საქაღალდეების სიას კითხულობს და ცარიელ შედეგს უარყოფს, თუმცა გამომძახებელს მაინც უწევს იმ შემთხვევისთვის ცალკე შტოს დაწერა, რომელიც ვერასდროს დადგება. ავტორის შეფასებით, ასეთი პირობები დროის ბომბს ჰგავს: კომპილატორი მათ არ ამოწმებს, ამიტომ მოგვიანებით ისინი ჩუმად შეიძლება დაირღვეს. გამოსავალი ცალკე ტიპია, მაგალითად nonempty crate-ის NonEmpty, რომელსაც ცარიელი მნიშვნელობის შექმნა არ შეუძლია და first() სუფთა მითითებას აბრუნებს. შემოწმებული Vec-ის დაბრუნება ვალიდაციაა, NonEmpty-ის დაბრუნება კი პარსინგი, თუ პარსინგს ფართოდ, მონაცემის ერთი ფორმატიდან მეორეში გადაქცევად გავიგებთ.
კონვეიერები, ბილიკები და ეტაპობრივი დაზუსტება
შემდეგ ესე სათამაშო კოდს სცდება. posixutils-rs პროექტში, რომელიც POSIX-ის ძირითადი უტილიტების Rust-ის ვერსიაა, shell-ის კონვეიერის ბრძანებები NonEmpty-ში ინახება, ამიტომ დამუშავებული კონვეიერი ყოველთვის მინიმუმ ერთ ბრძანებას შეიცავს, ხოლო პარსერი None-ს მხოლოდ მაშინ აბრუნებს, როცა გასაშვები არაფერია. rust-analyzer-ს აბსოლუტური ფაილის ბილიკის ცალკე ტიპი აქვს: გარდაქმნა ვერ შესრულდება, თუ ბილიკი აბსოლუტური არ არის, და შემდგომი კოდი ტიპს ეყრდნობა, პირობას კი ხელახლა აღარ ამოწმებს. Bendersky ამას ეტაპობრივ პარსინგს უწოდებს: ბილიკი ჯერ camino crate-ის მეშვეობით მოქმედ UTF-8-ად დასტურდება, შემდეგ კი აბსოლუტურად.
ნულოვანი რიცხვები და JSON
Rust-ის სტანდარტულ ბიბლიოთეკაში ზოგადი NonZero ტიპია იმ უნიშნო რიცხვებისთვის, რომლებიც ნულის ტოლი ნამდვილად არ არიან. available_parallelism ფუნქცია წარმატებისას სწორედ ასეთ მნიშვნელობას აბრუნებს, გაყოფა კი NonZero მნიშვნელით დოკუმენტაციით ის ოპერაციაა, რომელსაც პანიკა არ შეუძლია. ტიპს დამატებითი უპირატესობაც აქვს: ნული მისთვის არასწორი ბიტური მნიშვნელობაა, ამიტომ არასავალდებულო NonZero ზუსტად იმავე მეხსიერებას იკავებს, რასაც ჩვეულებრივი მთელი რიცხვი. იგივე იდეა JSON-ის დამუშავებაშიც ჩანს: serde-ს საშუალებით კონფიგურაციის სტრუქტურა ისე აღიწერება, რომ worker-ების რაოდენობა არანულოვანი იყოს, რეჟიმი კი ორმნიშვნელობიან enum-ად გამოცხადდეს; დესერიალიზაცია ველების ტიპებს, დაშვებულ მნიშვნელობებსა და ნულის აკრძალვას ერთდროულად ამოწმებს. დინამიურ ენებში ეს პროცესი გაცილებით ხელით საკეთებელია: Python-ის json.loads ლექსიკონს აბრუნებს და შემოწმებას გამომძახებელს ტოვებს, Pydantic-ის მსგავსი ბიბლიოთეკები კი Rust-ის მიდგომას უახლოვდებიან, თუმცა ყველგან არ გამოიყენება.
SiTech — AI-გაძლიერებული ვებ დეველოპმენტი
ვქმნით სწრაფ, თანამედროვე ვებსაიტებს და AI-ს ვაერთიანებთ ქართული ბიზნესებისთვის. გაქვთ პროექტი ან კითხვა? სიამოვნებით დაგეხმარებით.