Expérience de la conversion de code C # en code Rust

Formulation du problĂšme



Le code C # doit ĂȘtre traduit en code Rust. Plus prĂ©cisĂ©ment, une telle procĂ©dure de traduction est nĂ©cessaire (le dĂ©veloppement se poursuit en C #) pour qu'Ă  tout moment vous puissiez obtenir un code fonctionnel dans Rust. J'ai rĂ©solu ce problĂšme pour Java, Python, JavaScript et PHP en Ă©crivant un convertisseur de C # vers ces langages. Le concept d'une telle conversion a Ă©tĂ© dĂ©crit dans l'article d' UniSharping il y a quelques annĂ©es. Je dĂ©veloppais ce convertisseur pour traduire le code de mon projet Pullenti SDK (analyse de texte linguistique). Et j'ai pensĂ©: pourquoi ne pas essayer Rust? Oui, j'ai entendu diffĂ©rentes rĂ©ponses que le langage est inhabituel, etc., mais ce n'est pas une tentative de torture ... De plus, l'un des clients a un groupe de programmeurs qui y Ă©crivent avec enthousiasme.



Je dois dire tout de suite que cela n'a pas fonctionnĂ© dans son intĂ©gralitĂ©, comme pour les autres langues, - il n'y avait pas assez de force. Je reviendrai peut-ĂȘtre sur ce problĂšme. Un mois et demi a Ă©tĂ© passĂ© Ă  se battre avec moi-mĂȘme et la langue, nous avons rĂ©ussi Ă  amener le convertisseur au point que le bloc morphologique a commencĂ© Ă  traduire et mĂȘme Ă  compiler (et donc Ă  fonctionner) dans Rust. Bien sĂ»r, pendant ce temps, le module de morphologie pouvait ĂȘtre Ă©crit Ă  partir de zĂ©ro, mais derriĂšre il y avait environ 500 classes C # supplĂ©mentaires, crĂ©Ă©es et dĂ©boguĂ©es pendant prĂšs de 10 ans, et il n'est pas si facile de les rĂ©Ă©crire. Dans cet article, je souhaite partager mes impressions sur le langage Rust, ainsi que dĂ©crire les techniques que j'ai utilisĂ©es pour convertir.



Impression de la langue Rust



On dit que le maĂźtre ne cherche pas des moyens faciles. Cela s'applique pleinement Ă  Rust, car beaucoup de ce qui est simple et familier dans d'autres langues devient complexe, alors que le complexe ne devient pas simple. Vous semblez vous retrouver dans un autre monde avec Ă  premiĂšre vue une logique absurde, qui devient loin d'ĂȘtre immĂ©diatement comprĂ©hensible aprĂšs avoir maĂźtrisĂ© les concepts de base. Peu importe ce que vous avez Ă©crit jusqu'Ă  prĂ©sent: C ++, Java, Python, etc., mais quand il s'avĂšre qu'aprĂšs avoir ajoutĂ© un objet Ă  la liste, vous ne pouvez pas utiliser :, it = new ...(); list.add(it); it.val = ...mais vous pouvez le it = new ...(); it.val = ...; list.add(it);faire comme ceci :, c'est dĂ©courageant. Ou, pour implĂ©menter des rĂ©fĂ©rences croisĂ©es entre les objets de la classe Foo, vous devez utiliser la construction Option<Rc<RefCell<Foo>>>, et pour accĂ©der au champ val de cette classe, appelez foo.unwrap().borrow().val.



: , , . Rust , . ( Rust 20-). ? .



Rust — C# 2 . , , ( ). , , Rust C/C++ . . , Rust /C++, , ...



Rust , "" 50 , - , . 80- ( ), , . . - , trait- ( interface Java C#), - , . , , ? , Rust , .





Rust — (heap). — new/delete. \++, , . , delete . , . , , new. : Java, C#, Python, JavaScritp, PHP .



Rust , , , . , { ... let x = Foo {... }; ... }, . — - . , , (mut) , , . , , C# buf stream.Read(buf, 0, buf.Length) , buf mut-, buf . : int len = buf.Length; stream.Read(buf, 0, len);.



, C# Rust. , — .



C#



, SDK C# Java. , , . , , — C# , . . UniSharping. , . , C#, . , Java yield, C# — !

C# . Java DLL, Java . Python , , . JavaScript long ( byte, short, int, float, double, long- ), SDK C# long int, . PHP string utf-8 i- . , mb_, - . Rust , -.



C#, - : #if JAVA || PYTHON
 #else
 #endif — .



— . , , ? . Rust , .



, .





C#, , , — Rust , . for(...; ...; ...) while — . byte, int, float . , . .



T C# Rust : T ( ), &T ( ) &mut T ( ). , C# — C# , Rust , .



var obj = new T(); //    T
FuncNotModif(obj); //    
FuncModif(obj); //   
list.Add(obj); //    List<T>
var obj2 = obj; //      
var obj3 = obj; //      


Rust:



let obj = T { }; //    T (   )
func_not_modif(&obj); //   ,   obj   
func_modif(&mut obj); //    
list.push(&obj); //       Vec<&T>,   obj 
let obj2 : &T = &obj; //    
let obj3 : T = obj; //      obj3,  obj  obj2   


, Rust , : =, return &. , .



C# , : T, &T &mut T? , :



&T &mut T , ( ), , property { get; set; } &T, — T. C# /*&*/ /*&mut*/ . , List<T/*&*/>, , List<T/*&*/>/*&*/.



: , , , . , . — , . , .





Rust utf-8 ( PHP). , 2 . C#, Java . char 16 ( 8 , ++ 8 16), Rust. Unicode 32-, 64-? . — , 7- ASCII.



str[i]. ?



— (struct Rust), , string.



#[derive(Clone)]
pub struct NString {
    pub chars : Vec<char>,
    pub string : String,
    _is_null : bool
}
impl NString {
    pub fn from_string(s : &String) -> NString {
        NString { chars : s.chars().collect(), string : s.clone(), _is_null : false }
    }
    pub fn from_str(s : &str) -> NString {
        NString { chars : s.chars().collect(), string : s.to_string(), _is_null : false }
    }
    pub fn from_chars(s : &Vec<char>) -> NString {
        NString { chars : s.clone(), string : s.into_iter().collect(), _is_null : false }
    }
...
}


, chars, — String. C# , Rust. , Substring(int start, int len) :



    pub fn substring(&self, pos : i32, len : i32) -> NString {
        let length : i32 = if len <= 0 { self.chars.len() as i32 - pos } else { len };
        let sub = self.chars[pos as usize .. (pos + length) as usize].to_vec();
        NString::from_chars(&sub)
    }


- , &STR_HELLO STR_HELLO.clone() :



static STR_HELLO : Lazy<NString> = Lazy::new(|| { NString::from_str("Hello!") }); 
use once_cell::sync::Lazy;




, Rust , . , , C# , Vec HashMap . 3 : , &T T. array[] Rust , List.

Object



Rust null object, . , C# "" object "" — Rust . , .



object, object. , , , /*=*/ object.



            object/*=ObjValue*/ obj = "Hello";
            Console.WriteLine(obj);
            obj = 10;
            if (obj is int)
            {
                int ii = (int)obj;
                Console.WriteLine(ii);
            }
            obj = cnt.First; //   Item
            if(obj is Item)
                Console.WriteLine((obj as Item).Str);

#if RUST  //  C#   
        //RUST object_class
        class ObjValue
        {
            public string Str;
            public int Int;
            public Item/*&*/ Item;
        }
#endif


, object int, string Item, , Item — .



ObjValue, C#, .



        let mut obj : ObjValue = ObjValue::from_str_(STR_HELLO.clone());
        println!("{}", &obj.to_nstring());
        obj = ObjValue::from_int(10);
        if obj.is_class("i32") {
            let mut ii : i32 = obj.int;
            println!("{}", &NString::from_string(&ii.to_string()));
        }
        obj = ObjValue::from_item(Some(Rc::clone(cnt.borrow().get_first().as_ref().unwrap())));
        if obj.is_class("Item") {
            println!("{}", obj.item.as_ref().unwrap().borrow().get_str());
        }

pub struct ObjValue {
    pub str_ : NString, 
    pub int : i32, 
    pub item : Option<Rc<RefCell<dyn IItem>>>, 
    _typ : &'static str
}

impl ObjValue {
    pub fn from_str_(val : NString) -> ObjValue {
        ObjValue { str_ : val, int : 0, item : None, _typ : "NString" }
    }
    pub fn from_int(val : i32) -> ObjValue {
        ObjValue { str_ : NString::null(), int : val, item : None, _typ : "i32" }
    }
    pub fn from_item(val : Option<Rc<RefCell<dyn IItem>>>) -> ObjValue {
        ObjValue { str_ : NString::null(), int : 0, item : val, _typ : "Item" }
    }
    pub fn null() -> ObjValue {
        ObjValue { str_ : NString::null(), int : 0, item : None, _typ : "" }
    }
    pub fn is_null(&self) -> bool { self._typ.len() == 0 }
    pub fn is_class(&self, typ : &str) -> bool { self._typ == typ }
    pub fn to_nstring(&self) -> NString {
        if self._typ == "NString" { return self.str_.clone(); }
        if self._typ == "i32" { return NString::from_string(&self.int.to_string()); }
        if self._typ == "Item" { return NString::from_str("Option<Rc<RefCell<dyn IItem>>>"); }
        NString::null()
    }
}


, . ! , .

: obj = cnt.First Rust obj = ObjValue::from_item(Some(Rc::clone(cnt.borrow().get_first().as_ref().unwrap()))). , ? , ! , , .





C# Rust struct, — trait. , — . . C# , : . .



- - , .



. A, , trait, , get set ( property). struct B A (struct B { base : A, }), B trait A. A, self.base.x.

.



    //RUST RefCell
    class Item
    {
        public Item(int val) { Val = val; }
        public int Val { get; set; }
        public string Str;
        public Item/*&*/ Prev { get; set; }
        public Item/*&*/ Next { get; set; }
        public virtual void Inc() { Val += 1; }
    }
    //RUST RefCell
    class ItemChild : Item
    {
        public ItemChild(int val) : base(val) { }
        public override void Inc() { Val *= 2; }
    }


( ). trait.



pub trait IItem {
    fn get_val(&self) -> i32;
    fn set_val(&mut self, value : i32) -> i32;
    fn get_str(&self) -> &NString;
    fn set_str(&mut self, value : NString) -> &NString;
    fn get_prev(&self) -> &Option<Rc<RefCell<dyn IItem>>>;
    fn set_prev(&mut self, value : Option<Rc<RefCell<dyn IItem>>>) -> &Option<Rc<RefCell<dyn IItem>>>;
    fn get_next(&self) -> &Option<Rc<RefCell<dyn IItem>>>;
    fn set_next(&mut self, value : Option<Rc<RefCell<dyn IItem>>>) -> &Option<Rc<RefCell<dyn IItem>>>;
    fn inc(&mut self);
    fn get_base_class(&self) -> &dyn IItem;
    fn is_class(&self, name : &str) -> bool;
    fn as_item(&self) -> &dyn IItem;
    fn as_mut_item(&mut self) -> &mut dyn IItem;
}


.



pub struct Item {
    pub _val : i32, 
    pub m_str : NString, 
    pub _prev : Option<Rc<RefCell<dyn IItem>>>, 
    pub _next : Option<Rc<RefCell<dyn IItem>>>, 
}

impl IItem for Item {
    fn get_val(&self) -> i32 {
        return self._val;
    }
    fn set_val(&mut self, mut value : i32) -> i32 {
        self._val = value;
        return self._val;
    }
    fn get_prev(&self) -> &Option<Rc<RefCell<dyn IItem>>> {
        return &self._prev;
    }
    fn set_prev(&mut self, mut value : Option<Rc<RefCell<dyn IItem>>>) -> &Option<Rc<RefCell<dyn IItem>>> {
        self._prev = utils::clone_opt_ref(&value);
        return &self._prev;
    }
...
    fn inc(&mut self) {
        self.set_val(self.get_val() + 1);
    }
    fn as_item(&self) -> &dyn IItem { self }
    fn as_mut_item(&mut self) -> &mut dyn IItem { self }
    fn get_base_class(&self) -> &dyn IItem { self }
    fn is_class(&self, name : &str) -> bool { name == "Item" }
}

impl Item {
    pub fn new(mut __val : i32) -> Item {
        let mut self_result = Item {  _val : 0,  _prev : None,  _next : None,  m_str : NString::null() };
        self_result.set_val(__val);
        self_result
    }
}


:



pub struct ItemChild {
    pub base : Item, //   
}
impl IItem for ItemChild {
    fn get_val(&self) -> i32 {
        self.base.get_val()  //      base
    }
    fn set_val(&mut self, value : i32) -> i32 {
        self.base.set_val(value)
    }
    //   -     
    fn inc(&mut self) {
        self.base.set_val(self.get_val() * 2);
    }
    ....
}

impl ItemChild {
    pub fn new(mut __val : i32) -> ItemChild {
        ItemChild {  base : Item::new(__val) };
    }
}


Item ItemChild ITrait, inc() , trait — ! .





&T (lifetime), , , . , : struct A<'a> { ref : &'a Item, ... }. , 'a. . , , lifetime-hell, . , Rust !



: Option<Rc<RefCell<T>>>. . — , . , Option<Weak<RefCell<T>>>. " , , ! — , ..."





, , . SDK , 10% . , , . " " , , C# — Rust . .



, Rust , 
 , . Rust — , , , - ! !




All Articles