翻译çpreprocessor条锈 [英] Translating C preprocessor to Rust

查看:105
本文介绍了翻译çpreprocessor条锈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我移植一些C code生锈和code包含了很多这样的事情:

I'm porting some C code to Rust and that code contains a lot of things like this:

#define CONFIG_FLAG_NUMBER_23 1
#define THIS 10
#define THAT 11
#define THIS_AND_THAT (THIS + THAT)

#if CONFIG_FLAG_NUMBER_23
#define THIS_OR_THAT THIS
#else
#define THIS_OR_THAT THAT
#endif

#define ROOT_DIR "/root"
#define FILE_ONE ROOT_DIR "/file_one"
#define FILE_TWO ROOT_DIR "/file_two"

我决定删除宏和恒前pressions取代他们,但尝试做它在锈不很成功的:

I decided to remove macros and replace them with constant expressions, but the attempts to do it in Rust weren't very successful:

static CONFIG_FLAG: bool = true;
static THIS: int = 10;
static THAT: int = 11;
static THIS_AND_THAT: int = THIS + THAT; // Okay, it works

// 1: Conditions
static THIS_OR_THAT: int = CONFIG_FLAG ? THIS : THAT; // Doesn't work, no conditional operator
static THIS_OR_THAT: int = if CONFIG_FLAG { THIS } else { THAT }; // Doesn't work, "if" is not basic enough for compile time

// 2: Strings
static ROOT_DIR: &'static str = "/root";
static FILE_ONE: &'static str = ROOT_DIR + "/file_one"; // Doesn't work, static strs can't be Added
static FILE_TWO: String = ROOT_DIR.to_string() + "/file_two"; // Don't even think about allocations in constant expressions!
static FILE_THREE: &'static str = concat!(ROOT_DIR, "/file_three"); // Doesn't work, concat! works only with literals

什么是重写拉斯特这样code正确/不费力的方式?

What would be the correct / least painful way to rewrite such code in Rust?

推荐答案

问题1:有条件的前pressions 结果
因为配置标志可以是PTED为整数除$ P $,它们可以在变体的阵列被用作索引。

Problem 1: Conditional expressions
Since configuration flags can be interpreted as integers, they can be used as indexes in arrays of variants.

// Configuration flag
static CONFIG_FLAG: uint = 1;

// Variants of any static type
type T = &'static str;
static VARIANT1: T = "True";
static VARIANT2: T = "False";

// Now you can select, but you have to invert either flag, or variants, or your brain
static SELECTED: T = [VARIANT1, VARIANT2][1 - CONFIG_FLAG];

fn main() {
    println!("{}", SELECTED);
}

注:

CONFIG_FLAG bool类型目前不会,因为问题的#5873

CONFIG_FLAG of type bool currently doesn't work in array index because of issue #5873,

// error: can't cast str to uint
static SELECTED: T = [VARIANT1, VARIANT2][1 - CONFIG_FLAG_BOOL as uint];

因此​​,你必须创建一个更静态的项目,然后在条件语句中使用它。

therefore you have to create one more static item and then use it in conditionals.

static CONFIG_FLAG_UINT: uint = CONFIG_FLAG_BOOL as uint;

问题2:编译时字符串连接

简单的C宏很好地映射到铁锈宏,所以你可以用基本相同的方法进行字符串连接为C.
唯一的区别是,你必须明确地使用CONCAT!而不是只将文字彼此相邻

Simple C macros nicely map into Rust macros, so you can use essentially the same approach for string concatenation as in C. The only difference is that you have to explicitly use concat! instead of just placing literals next to each other.

#![feature(macro_rules)]

// Define new macro-string with name $name assembled from arguments $arg
macro_rules! define_str (
    ($name: ident, $($arg: expr), +)
    =>
    (macro_rules! $name (
        () => (concat!($($arg), +))
    ));
)

// Some strings
define_str!(ROOT_DIR, "/root")
define_str!(SUB_DIR, ROOT_DIR!(), "/sub")
define_str!(FILE_NAME, SUB_DIR!(), "/file")
define_str!(NONSENSE, FILE_NAME!(), SUB_DIR!(), ROOT_DIR!())

fn main() {
    println!("{}", FILE_NAME!());
    println!("{}", NONSENSE!());
}

注:结果
我想补充!()来宏名自动在 define_str 与这样的附加宏

Notes:
I wanted to add !() to macro names automatically inside of define_str with additional macro like this,

macro_rules! add_bang_and_parens (
    ($arg: ident) => ($arg!());
    ($arg: expr) => ($arg);
)

但它似乎是在基于参数类型的宏模式匹配目前不可能。

but it seems like in macros pattern matching based on "types" of arguments is not currently possible.

这篇关于翻译çpreprocessor条锈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆