Nutype เป็นมาโคร PROC ที่อนุญาตให้เพิ่มข้อ จำกัด พิเศษเช่น การฆ่าเชื้อ และ การตรวจสอบความถูกต้อง ในรูปแบบ newType ปกติ รหัสที่สร้างขึ้นทำให้ไม่สามารถสร้างอินสแตนซ์ค่าโดยไม่ผ่านการตรวจสอบ มันใช้งานได้ด้วยวิธีนี้แม้จะมี serde Deserialization
use nutype :: nutype ;
// Define newtype Username
# [ nutype (
sanitize ( trim , lowercase ) ,
validate ( not_empty , len_char_max = 20 ) ,
derive ( Debug , PartialEq , Clone ) ,
) ]
pub struct Username ( String ) ;
// We can obtain a value of Username with `::try_new()`.
// Note that Username holds a sanitized string
assert_eq ! (
Username :: try_new ( " FooBar " ) . unwrap ( ) . into_inner ( ) ,
"foobar"
) ;
// It's impossible to obtain an invalid Username
// Note that we also got `UsernameError` enum generated implicitly
// based on the validation rules.
assert_eq ! (
Username :: try_new ( " " ) ,
Err ( UsernameError :: NotEmptyViolated ) ,
) ;
assert_eq ! (
Username :: try_new ( "TheUserNameIsVeryVeryLong" ) ,
Err ( UsernameError :: LenCharMaxViolated ) ,
) ;สำหรับข้อมูลเพิ่มเติมโปรดดู:
sanitizers ที่มีอยู่การตรวจสอบและลักษณะที่ได้รับจะถูกกำหนดโดยประเภทภายในซึ่งอยู่ในหมวดหมู่ต่อไปนี้:
u8 , u16 , u32 , u64 , u128 , i8 , i16 , i32 , i64 , i128 , usize , isize )f32 , f64 ) ในขณะนี้ประเภทของสตริงภายในรองรับประเภท String (เป็นเจ้าของ) เท่านั้น
| ผู้ฆ่าเชื้อ | คำอธิบาย | ตัวอย่าง |
|---|---|---|
trim | ลบช่องว่างชั้นนำและตามท้าย | trim |
lowercase | แปลงสตริงเป็นตัวพิมพ์เล็ก | lowercase |
uppercase | แปลงสตริงเป็นตัวพิมพ์ใหญ่ | uppercase |
with | ผู้ฆ่าเชื้อที่กำหนดเอง ฟังก์ชั่นหรือการปิดที่ได้รับ String และส่งคืน String | with = |mut s: String| ( s.truncate(5); s ) |
| ผู้ตรวจสอบความถูกต้อง | คำอธิบาย | ตัวแปรข้อผิดพลาด | ตัวอย่าง |
|---|---|---|---|
len_char_min | ความยาวขั้นต่ำของสตริง (เป็นตัวอักษรไม่ใช่ไบต์) | LenCharMinViolated | len_char_min = 5 |
len_char_max | ความยาวสูงสุดของสตริง (เป็นตัวอักษรไม่ใช่ไบต์) | LenCharMaxViolated | len_char_max = 255 |
not_empty | ปฏิเสธสตริงว่างเปล่า | NotEmptyViolated | not_empty |
regex | ตรวจสอบรูปแบบด้วย regex ต้องใช้คุณสมบัติ regex | RegexViolated | regex = "^[0-9]{7}$" หรือ regex = ID_REGEX |
predicate | ตัวตรวจสอบความถูกต้องที่กำหนดเอง ฟังก์ชั่นหรือการปิดที่ได้รับ &str และส่งคืน bool | PredicateViolated | predicate = |s: &str| s.contains('@') |
with | ตัวตรวจสอบความถูกต้องที่กำหนดเองพร้อมข้อผิดพลาดที่กำหนดเอง | N/A | (ดูตัวอย่างด้านล่าง) |
ความต้องการ:
regex ของ nutyperegex อย่างชัดเจนว่าเป็นการพึ่งพามีหลายวิธีที่คุณสามารถใช้ Regex
การแสดงออกปกติสามารถกำหนดได้อย่างถูกต้องในสถานที่:
# [ nutype ( validate ( regex = "^[0-9]{3}-[0-9]{3}$" ) ) ]
pub struct PhoneNumber ( String ) ; หรือสามารถกำหนดด้วย std::sync::LazyLock :
use regex :: Regex ;
static PHONE_NUMBER_REGEX : LazyLock < Regex > = LazyLock :: new ( || Regex :: new ( "^[0-9]{3}-[0-9]{3}$" ) . unwrap ( ) ) ;
# [ nutype ( validate ( regex = PHONE_NUMBER_REGEX ) ) ]
pub struct PhoneNumber ( String ) ; หรือสามารถกำหนดด้วย lazy_static :
use lazy_static :: lazy_static ;
use regex :: Regex ;
lazy_static ! {
static ref PHONE_NUMBER_REGEX : Regex = Regex :: new ( "^[0-9]{3}-[0-9]{3}$" ) . unwrap ( ) ;
}
# [ nutype ( validate ( regex = PHONE_NUMBER_REGEX ) ) ]
pub struct PhoneNumber ( String ) ; หรือ once_cell :
use once_cell :: sync :: Lazy ;
use regex :: Regex ;
static PHONE_NUMBER_REGEX : Lazy < Regex > =
Lazy :: new ( || Regex :: new ( "[0-9]{3}-[0-9]{3}$" ) . unwrap ( ) ) ;
# [ nutype ( validate ( regex = PHONE_NUMBER_REGEX ) ) ]
pub struct PhoneNumber ( String ) ; ลักษณะดังต่อไปนี้สามารถได้รับสำหรับประเภทสตริง: Debug , Clone , PartialEq , Eq , PartialOrd , Ord , FromStr , AsRef , Deref , From , TryFrom , Into , Hash , Borrow , Display , Default , Serialize , Deserialize
ประเภทภายในจำนวนเต็มคือ: u8 , u16 , u32 , u64 , u128 , i8 , i16 , i32 , i64 , i128 , usize , isize
| ผู้ฆ่าเชื้อ | คำอธิบาย | ตัวอย่าง |
|---|---|---|
with | ผู้ฆ่าเชื้อที่กำหนดเอง | with = |raw| raw.clamp(0, 100) |
| ผู้ตรวจสอบความถูกต้อง | คำอธิบาย | ตัวแปรข้อผิดพลาด | ตัวอย่าง |
|---|---|---|---|
less | ขอบเขตบนสุดพิเศษ | LessViolated | less = 100 |
less_or_equal | รวมขอบเขตบน | LessOrEqualViolated | less_or_equal = 99 |
greater | ขอบเขตล่างสุดพิเศษ | GreaterViolated | greater = 17 |
greater_or_equal | ขอบเขตล่างแบบรวม | GreaterOrEqualViolated | greater_or_equal = 18 |
predicate | เพรดิเคตที่กำหนดเอง | PredicateViolated | predicate = |num| num % 2 == 0 |
with | ตัวตรวจสอบความถูกต้องที่กำหนดเองพร้อมข้อผิดพลาดที่กำหนดเอง | N/A | (ดูตัวอย่างด้านล่าง) |
ลักษณะดังต่อไปนี้สามารถได้รับสำหรับประเภทจำนวนเต็ม: Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , FromStr , AsRef , Deref , Into , From , TryFrom , Hash , Borrow , Display , Default , Serialize , Deserialize
ประเภทภายในลอยคือ: f32 , f64
| ผู้ฆ่าเชื้อ | คำอธิบาย | ตัวอย่าง |
|---|---|---|
with | ผู้ฆ่าเชื้อที่กำหนดเอง | with = |val| val.clamp(0.0, 100.0) |
| ผู้ตรวจสอบความถูกต้อง | คำอธิบาย | ตัวแปรข้อผิดพลาด | ตัวอย่าง |
|---|---|---|---|
less | ขอบเขตบนสุดพิเศษ | LessViolated | less = 100.0 |
less_or_equal | รวมขอบเขตบน | LessOrEqualViolated | less_or_equal = 100.0 |
greater | ขอบเขตล่างสุดพิเศษ | GreaterViolated | greater = 0.0 |
greater_or_equal | ขอบเขตล่างแบบรวม | GreaterOrEqualViolated | greater_or_equal = 0.0 |
finite | ตรวจสอบกับน่านและอินฟินิตี้ | FiniteViolated | finite |
predicate | เพรดิเคตที่กำหนดเอง | PredicateViolated | predicate = |val| val != 50.0 |
with | ตัวตรวจสอบความถูกต้องที่กำหนดเองพร้อมข้อผิดพลาดที่กำหนดเอง | N/A | (ดูตัวอย่างด้านล่าง) |
ลักษณะดังต่อไปนี้สามารถได้รับสำหรับประเภทลอย: Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , FromStr , AsRef , Deref , Into , From , TryFrom , Hash , Borrow , Display , Default , Serialize , Deserialize
นอกจากนี้ยังเป็นไปได้ที่จะได้รับ Eq และ Ord หากกฎการตรวจสอบความถูกต้องรับประกันว่า NaN ไม่รวมอยู่ สิ่งนี้สามารถทำได้โดยการตรวจสอบ finite ตัวอย่างเช่น:
# [ nutype (
validate ( finite ) ,
derive ( PartialEq , Eq , PartialOrd , Ord ) ,
) ]
struct Size ( f64 ) ; สำหรับประเภทอื่น ๆ มันเป็นไปได้ที่จะกำหนด sanitizers ที่กำหนดเอง with และการตรวจสอบความถูกต้องที่กำหนดเองด้วย predicate :
use nutype :: nutype ;
# [ nutype (
derive ( Debug , PartialEq , AsRef , Deref ) ,
sanitize ( with = | mut guests| { guests . sort ( ) ; guests } ) ,
validate ( predicate = |guests| !guests . is_empty ( ) ) ,
) ]
pub struct GuestList ( Vec < String > ) ;นอกจากนี้ยังเป็นไปได้ที่จะใช้ยาสามัญ:
# [ nutype (
sanitize ( with = | mut v| { v . sort ( ) ; v } ) ,
validate ( predicate = |vec| !vec . is_empty ( ) ) ,
derive ( Debug , PartialEq , AsRef , Deref ) ,
) ]
struct SortedNotEmptyVec < T : Ord > ( Vec < T > ) ;
let wise_friends = SortedNotEmptyVec :: try_new ( vec ! [ "Seneca" , "Zeno" , "Plato" ] ) . unwrap ( ) ;
assert_eq ! ( wise_friends . as_ref ( ) , & [ "Plato" , "Seneca" , "Zeno" ] ) ;
assert_eq ! ( wise_friends . len ( ) , 3 ) ;
let numbers = SortedNotEmptyVec :: try_new ( vec ! [ 4 , 2 , 7 , 1 ] ) . unwrap ( ) ;
assert_eq ! ( numbers . as_ref ( ) , & [ 1 , 2 , 4 , 7 ] ) ;
assert_eq ! ( numbers . len ( ) , 4 ) ; คุณสามารถตั้งค่า sanitizers ที่กำหนดเองโดยใช้ตัวเลือก with เจลทำความสะอาดที่กำหนดเองเป็นฟังก์ชั่นหรือการปิดที่ได้รับค่าของประเภทภายในที่มีความเป็นเจ้าของและส่งคืนค่าที่ถูกสุขลักษณะ
ตัวอย่างเช่นอันนี้
# [ nutype ( sanitize ( with = new_to_old ) ) ]
pub struct CityName ( String ) ;
fn new_to_old ( s : String ) -> String {
s . replace ( "New" , "Old" )
}เท่ากับหนึ่งต่อไปนี้:
# [ nutype ( sanitize ( with = |s| s . replace ( "New" , "Old" ) ) ) ]
pub struct CityName ( String ) ;และทำงานในลักษณะเดียวกัน:
let city = CityName :: new ( "New York" ) ;
assert_eq ! ( city . into_inner ( ) , "Old York" ) ; ในทำนองเดียวกันมันเป็นไปได้ที่จะกำหนดตัวตรวจสอบที่กำหนดเอง แต่ฟังก์ชั่นการตรวจสอบความถูกต้องได้รับการอ้างอิงและส่งคืน bool คิดว่ามันเป็นภาคแสดง
# [ nutype ( validate ( predicate = is_valid_name ) ) ]
pub struct Name ( String ) ;
fn is_valid_name ( name : & str ) -> bool {
// A fancy way to verify if the first character is uppercase
name . chars ( ) . next ( ) . map ( char :: is_uppercase ) . unwrap_or ( false )
} ในการกำหนดประเภทข้อผิดพลาดของคุณเองและใช้ตรรกะการตรวจสอบความถูกต้องที่กำหนดเองคุณสามารถรวมแอตทริบิวต์ with และข้อ error :
// Define a custom error type for validation failures.
// Although it's best practice to implement `std::error::Error` for custom error types,
// we are omitting that for simplicity here.
# [ derive ( Debug , PartialEq ) ]
enum NameError {
TooShort ,
TooLong ,
}
// Define a custom validation function for `Name`.
// The function returns `Result<(), NameError>`, where `Ok(())` indicates a valid name,
// and `Err(NameError)` represents a specific validation failure.
fn validate_name ( name : & str ) -> Result < ( ) , NameError > {
if name . len ( ) < 3 {
Err ( NameError :: TooShort )
} else if name . len ( ) > 10 {
Err ( NameError :: TooLong )
} else {
Ok ( ( ) )
}
}
// Define a newtype `Name` with custom validation logic and custom error.
# [ nutype (
validate ( with = validate_name , error = NameError ) ,
derive ( Debug , PartialEq ) ,
) ]
struct Name ( String ) ; สิ่งสำคัญคือต้องแน่ใจว่าประเภทที่ระบุในแอตทริบิวต์ error ตรงกับประเภทข้อผิดพลาดที่ส่งคืนโดยฟังก์ชันการตรวจสอบความถูกต้อง
Default # [ nutype (
derive ( Default ) ,
default = "Anonymous" ,
) ]
pub struct Name ( String ) ;Eq และ Ord ในประเภทลอยตัว ด้วย nutype เป็นไปได้ที่จะได้รับ Eq และ Ord หากมีชุดการตรวจสอบ finite การตรวจสอบ finite ทำให้มั่นใจได้ว่าค่าที่ถูกต้องไม่รวม NaN
# [ nutype (
validate ( finite ) ,
derive ( PartialEq , Eq , PartialOrd , Ord ) ,
) ]
pub struct Weight ( f64 ) ; มันท้อแท้ แต่เป็นไปได้ที่จะหลีกเลี่ยงข้อ จำกัด โดยการเปิดใช้งานฟีเจอร์ Crate new_unchecked และทำเครื่องหมายประเภทด้วย new_unchecked :
# [ nutype (
new_unchecked ,
sanitize ( trim ) ,
validate ( len_char_min = 8 )
) ]
pub struct Name ( String ) ;
// Yes, you're forced to use `unsafe` here, so everyone will point fingers at YOU.
let name = unsafe { Name :: new_unchecked ( " boo " . to_string ( ) ) } ;
// `name` violates the sanitization and validation rules!!!
assert_eq ! ( name . into_inner ( ) , " boo " ) ; arbitrary - ช่วยให้ได้มาจาก arbitrary::Arbitrarynew_unchecked - เปิดใช้งานการสร้างฟังก์ชั่น unsafe ::new_unchecked()regex - อนุญาตให้ใช้ regex = การตรวจสอบความถูกต้องในประเภทที่ใช้สตริง หมายเหตุ: ลังของคุณยังต้องมี regex อย่างชัดเจนภายในการพึ่งพาserde - การรวมเข้ากับ serde Crate ช่วยให้ได้รับ Serialize และ Deserialize ลักษณะschemars08 - อนุญาตให้ได้รับคุณสมบัติ JsonSchema ของ Schemars Crate โปรดทราบว่าในขณะนี้กฎการตรวจสอบความถูกต้องไม่ได้รับการเคารพstd - เปิดใช้งานโดยค่าเริ่มต้น ใช้ default-features = false เพื่อปิดการใช้งาน วันนี้ฉันอาศัยอยู่ในเบอร์ลินฉันมีความหรูหราที่จะใช้ชีวิตที่ปลอดภัยทางร่างกาย แต่ฉันเป็นชาวยูเครน 25 ปีแรกในชีวิตของฉันที่ฉันใช้ใน Kharkiv ซึ่งเป็นเมืองที่ใหญ่เป็นอันดับสองในยูเครนห่างจากชายแดนกับรัสเซีย 60 กม. วันนี้ประมาณหนึ่งในสามของเมืองบ้านเกิดของฉันถูกทำลายโดยรัสเซีย พ่อแม่ของฉันญาติของฉันและเพื่อนของฉันต้องอยู่รอดจากปืนใหญ่และการโจมตีทางอากาศอาศัยอยู่นานกว่าหนึ่งเดือนในห้องใต้ดิน
บางคนจัดการเพื่ออพยพไปยังสหภาพยุโรป บางคนพยายามใช้ชีวิต "ชีวิตปกติ" ใน Kharkiv ทำหน้าที่ประจำวัน และบางคนก็อยู่ที่แนวหน้าในขณะนี้เสี่ยงชีวิตทุกวินาทีเพื่อปกป้องคนอื่น ๆ
ฉันขอแนะนำให้คุณบริจาคให้กับมูลนิธิการกุศลของ Serhiy Prytula เพียงแค่เลือกโครงการที่คุณชอบและบริจาค นี่เป็นหนึ่งในมูลนิธิที่รู้จักกันดีที่สุดคุณสามารถดูสารคดีเล็ก ๆ น้อย ๆ เกี่ยวกับเรื่องนี้ การมีส่วนร่วมของคุณในกองกำลังทหารยูเครนเป็นส่วนหนึ่งของความสงบของฉันดังนั้นฉันจึงสามารถใช้เวลาพัฒนาโครงการได้มากขึ้น
ขอบคุณ
MIT © Serhii Potapov