我正在将我的一个 C++ 项目(一个简单的 DSL)转换为 rust 作为学习 rust 的练习,但我在嵌套结构和所有权方面遇到了麻烦。我很难转换一些东西,比如:
struct FileData {
bool is_utf8;
std::string file_name;
};
class Token {
public:
enum TokenType {
REGULAR,
INCLUDE_FILE,
}
Token() {
_type = REGULAR;
}
Type get_type() const { return _type; }
void beginIncludeFile() {
_type = INCLUDE_FILE;
_include_data = std::unique_ptr<FileData>(new FileData);
}
bool is_utf8() const {
assert(get_type() == INCLUDE_FILE);
return _include_data->is_utf8;
}
void set_utf8(bool value) {
assert(get_type() == INCLUDE_FILE);
_include_data->is_utf8 = value;
}
const std::string& get_file_name() const {
assert(get_type() == INCLUDE_FILE);
return _include_data->file_name;
}
void setFileNameToEmpty() {
assert(get_type() == INCLUDE_FILE);
_include_data->file_name = "";
}
void appendToFileName(char c) {
assert(get_type() == INCLUDE_FILE);
_include_data->file_name += c;
}
FileData* releaseFileData() { return _include_data.release(); }
private:
std::unique_ptr<FileData> _include_data;
TokenType _type;
};
我要为此写的锈是:
use std::str;
pub struct FileData {
is_utf8 : bool,
file_name : ~str
}
pub fn FileData() -> FileData {
FileData { is_utf8 : true, file_name : ~"" }
}
enum TokenType {
REGULAR,
INCLUDE_FILE
}
pub struct Token {
priv _include_data : Option<~FileData>,
priv _type : TokenType
}
pub fn Token() -> Token {
Token {
_include_data: None,
_type : REGULAR
}
}
impl Token {
pub fn get_type(&self) -> TokenType {
self._type
}
pub fn beginIncludeFile(&mut self) {
self._type = INCLUDE_FILE;
self._include_data = Some(~FileData());
}
pub fn is_utf8(&self) -> bool {
match self._include_data {
Some(ref data) => data.is_utf8,
_ => fail!("No FileData")
}
}
pub fn set_utf8(&mut self, value : bool) {
self._include_data.mutate(|mut data| {
data.is_utf8 = value;
data
});
}
// Return immutable/read-only copy
pub fn get_file_name(&self) -> &~str {
match self._include_data {
Some(ref data) => &data.file_name,
_ => fail!("No FileData")
}
}
pub fn setFileNameToEmpty(&mut self) {
match self._include_data {
Some(ref data) => data.file_name = ~"",
_ => fail!("No FileData")
}
return;
}
pub fn appendToFileName(&mut self, c : char) {
match self._include_data {
Some(ref data) => data.file_name.push_char(c),
_ => fail!("No FileData")
}
return;
}
pub fn getIncludeData(&mut self) -> ~FileData {
match self._include_data {
Some(ref data) => *data,
_ => fail!("No FileData")
}
}
}
enum LexState {
INITIAL,
EXPECT_COLON,
EXPECT_ENCODING,
EXPECT_QUOTE,
IN_FILENAME_STRING,
EXPECT_SEMI
}
impl Eq for LexState {
fn eq(&self, other: &LexState) -> bool {
return (*self as int) == (*other as int);
}
fn ne(&self, other: &LexState) -> bool {
!self.eq(other)
}
}
fn main() {
let mut t = ~Token();
let input = ~"include:utf8 \"file_path/file.foo\";";
let iter = input.iter();
let mut buf : ~str = ~"";
let mut state : LexState = INITIAL;
let buf_action = |action : &fn()| {
buf = ~"";
action();
};
while true {
let c = iter.next();
match c {
None => break,
Some(_c) => buf.push_char(_c)
}
match buf {
// Initial state
~"include" if state == INITIAL => buf_action(|| {
t.beginIncludeFile();
state = EXPECT_COLON;
}),
// Expecting either an encoding, or the start of the file name
~":" if state == EXPECT_COLON => buf_action(|| { state = EXPECT_ENCODING; }),
_ if state == EXPECT_COLON => state = EXPECT_QUOTE, // match WS
// utf8 is the only encoding accepted at the moment
~"utf8" if state == EXPECT_ENCODING => buf_action(|| {
t.set_utf8(true);
state = EXPECT_QUOTE;
}),
_ if state == EXPECT_ENCODING => t.set_utf8(false),
// Looking for string start
~"\"" if state == EXPECT_QUOTE => buf_action(||{ state = IN_FILENAME_STRING; }),
_ if state == EXPECT_QUOTE => (), // ignore other chars
// Reading filename
~"\"" if state == IN_FILENAME_STRING => buf_action(|| {
state = EXPECT_SEMI;
}),
_ if state == IN_FILENAME_STRING => t.appendToFileName(c.unwrap()),
// End of lex
~":" if state == EXPECT_SEMI => break,
_ if state == EXPECT_SEMI => fail!("Expected semi"),
_ => fail!("Unexpected character: " + str::from_char(c.unwrap()))
}
}
return;
}
这种代码的惯用生锈方式是什么?