Nutype هو ماكرو Proc يسمح بإضافة قيود إضافية مثل التعقيم والتحقق من صحة نمط NewType العادي. الرمز الذي تم إنشاؤه يجعل من المستحيل إنشاء قيمة دون تمرير الشيكات. إنه يعمل بهذه الطريقة حتى مع إلغاء التخلص من serde .
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 ) ,
) ;للمزيد من فضلك انظر:
يتم تحديد المطهرات المتاحة والمقاواة والسمات التي يمكن الاشتقاق بها من خلال النوع الداخلي ، الذي يندرج في الفئات التالية:
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 | دقيقة طول السلسلة (في chars ، وليس البايتات) | LenCharMinViolated | len_char_min = 5 |
len_char_max | كحد أقصى طول السلسلة (في chars ، وليس البايت) | 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 | مصلحة مخصصة مع خطأ مخصص | ن/أ | (انظر المثال أدناه) |
متطلبات:
regex من nutype .regex بشكل صريح كاعتماد.هناك عدد من الطرق التي يمكنك من خلالها استخدام 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 | مصلحة مخصصة مع خطأ مخصص | ن/أ | (انظر المثال أدناه) |
يمكن اشتقاق السمات التالية من أجل نوع قائم على عدد صحيح: 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 | مصلحة مخصصة مع خطأ مخصص | ن/أ | (انظر المثال أدناه) |
يمكن اشتقاق السمات التالية من أجل نوع قائم على التعويم: 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 ) ; بالنسبة لأي نوع آخر ، من الممكن تحديد المطورين المخصصين 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 ) ; يمكنك تعيين المطورين المخصص باستخدام الخيار 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 ) ; إنه أمر محبط ، ولكن من الممكن تجاوز القيود من خلال تمكين ميزة new_unchecked Crate ووضع علامة على نوع مع 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::Arbitrary .new_unchecked - تمكين توليد وظيفة غير آمنة ::new_unchecked() .regex - يسمح باستخدام regex = التحقق من الصحة على أنواع القائمة. ملاحظة: يجب أن يكون صندوقك أيضًا أن يكون لديه regex ضمن تبعياته.serde - تكامل مع serde Crate. يسمح لاستخلاص السمات Serialize Deserialize السمات.schemars08 - يسمح باستخلاص سمة JsonSchema من قفص المخططات. لاحظ أنه في الوقت الحالي لا يتم احترام قواعد التحقق من الصحة.std - تمكين افتراضيا. استخدم default-features = false لتعطيل. اليوم أعيش في برلين ، لديّ رفاهية لأعيش حياة آمنة جسديًا. لكني أوكرانية. أول 25 عامًا من حياتي قضيتها في خاركيف ، ثاني أكبر مدينة في أوكرانيا ، على بعد 60 كم من الحدود مع روسيا. اليوم حوالي ثلث مدينتي دمرها الروس. كان على والدي وأقاربي وأصدقائي البقاء على قيد الحياة من المدفعية والهجوم الجوي ، الذين يعيشون لأكثر من شهر في الطوابق السفلية.
تمكن بعضهم من الإخلاء إلى الاتحاد الأوروبي. يحاول البعض الآخر أن يعيش "حياة طبيعية" في خاركيف ، ويقومون هناك واجبات يومية. والبعض الآخر في خط المواجهة في الوقت الحالي ، ويخاطرون بحياتهم كل ثانية لحماية البقية.
أشجعك على التبرع لمؤسسة Serhiy Prytula الخيرية. فقط اختر المشروع الذي تعجبك وتبرع. هذه واحدة من أفضل المؤسسات المعروفة ، يمكنك مشاهدة فيلم وثائقي صغير عنه. إن مساهمتك في القوة العسكرية الأوكرانية هي مساهمة في هدوبي ، حتى أتمكن من قضاء المزيد من الوقت في تطوير المشروع.
شكرًا لك.
MIT © Serhii Potapov