问题的提法
需要将C#代码转换为Rust代码。更准确地说,需要这样的翻译过程(在C#中继续开发),以便您可以随时在Rust中获得有效的代码。我为Java,Python,JavaScript和PHP语言解决了这个问题,编写了从C#到这些语言的转换器。几年前在UniSharping文章中概述了这种转换的概念。我正在开发此转换器以翻译我的Pullenti SDK项目(语言文本分析)的代码。我想:为什么不试试Rust?是的,我听到了不同的回应,说这种语言是不寻常的,等等,但这不是一种折磨的尝试……而且,其中一位客户有一群热情地用它编写程序的程序员。
我必须立即说,它无法像其他语言那样完全解决-没有足够的力量。也许我会回到这个问题。花了一个半月的时间与自己和语言进行斗争,我们设法将转换器带到了形态块开始在Rust中进行翻译甚至编译(并因此工作)的地步。当然,在这段时间里,形态模块可以从头开始编写,但是在其后面隐约可见约有500个C#类,它们创建和调试了将近10年,重写它们并不是那么容易。在本文中,我想分享我对Rust语言的印象,并描述我用来转换的技术。
Rust语言的印象
据说,大师并不是在寻找简单的方法。这完全适用于Rust,因为其他语言中许多简单而又熟悉的东西都变得很复杂,而复杂性并不会变得简单。乍一看,您似乎发现自己处于另一个世界,这荒谬的逻辑在掌握了基本概念之后变得难以立即理解。到目前为止,您所写的内容都没有关系:C ++,Java,Python等,但是事实证明,在将对象添加到列表之后,您不能使用:,it = new ...(); list.add(it); it.val = ...
但是您可以像这样进行操作:it = new ...(); it.val = ...; list.add(it);
令人沮丧。或者,要在Foo类的对象之间实现交叉引用,您需要使用构造Option<Rc<RefCell<Foo>>>
,并访问此类的val字段,请调用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 — , , , - ! !