指定可变长度静态切片的方法

anu*_*ula 5 type-mismatch rust

假设我有一个具有以下签名的函数:

fn validate(samples: &[(&str, &[Token])])
Run Code Online (Sandbox Code Playgroud)

Token自定义枚举在哪里。我希望能够写一些类似的东西:

    let samples = vec![
        ("a string", &[Token::PLUS, Token::MINUS, Token::PLUS]),
        ("another string", &[Token::MUL]),
    ];
    validate(&samples);
Run Code Online (Sandbox Code Playgroud)

但是这样的代码会产生类型不匹配的编译错误:

error: mismatched types:
expected `&[(&str, &[Token])]`,
   found `&collections::vec::Vec<(&str, &[Token; 3])>`
Run Code Online (Sandbox Code Playgroud)

是否有可能以某种方式将具有静态长度()的版本转换&[Token; 3]为静态切片(&[Token])?换句话说,我希望能够以与我指定类似的方式指定静态切片&str,作为某种“切片文字”。

或者我做的完全错误?

编辑:简而言之,我想找到一种语法来创建具有静态生命周期(或至少与向量samples的生命周期一样长的生命周期)的数组,并返回它的切片。

类似于字符串的工作方式,只需输入“a string”即可给我 type 的引用&'static str

编辑2:@Pablo 的答案为我的特定问题提供了很好的解决方案,尽管这并不完全是我一开始的意思。

我想我所想到的确切的事情可能是不可能的,所以我现在只会接受这个,除非出现更符合我最初想法的东西。

Pab*_*blo 3

\n

简而言之,我想找到一种语法来创建一个具有静态生命周期(或至少与样本向量一样长的生命周期)的数组,并返回它的切片。

\n
\n\n

你\xe2\x80\x99d想要这样的东西:

\n\n
fn sliced(array: [Token; 3]) -> &\'static [Token] { unimplemented!() }\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以你可以在你的例子中这样使用它:

\n\n
let samples: Vec<(&str, &[Token])> = vec![\n    ("a string", sliced([Token::PLUS, Token::MINUS, Token::PLUS])),\n    // ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

但它有两个问题。第一个也是最明显的一点是,您可以\xe2\x80\x99tstatic从不\xe2\x80\x99t 接受的函数中获取引用。static(在这种情况下,它只会返回引用)。

\n\n

因此,由于您希望切片至少与数组一样长寿,因此要么声明const/static切片(这还需要其数组的const/static声明),要么首先使用语句声明数组let,然后创建切片。(这是我在下面的第一个替代方案中所做的。)如果您在 的使用中创建数组vec!及其切片,则数组会以以下方式结束其生命vec!,从而使切片无效。作为一个例子,考虑一下这个,由于同样的原因而失败:

\n\n
fn main() {\n    let slice;\n    {\n        let array: [u8; 3] = [1,2,3];\n        slice = &array;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

sliced函数的第二个问题是它的输入数组具有固定大小,并且您\xe2\x80\x99d 希望一般地处理任意大小的数组。然而,Rust [1]目前不支持这一点。您必须使用切片才能处理任意大小的数组。

\n\n

那么,一种可能性是执行以下操作 [ playpen ]:

\n\n
enum Token {\n    PLUS,\n    MINUS,\n    MUL,\n}\n\nfn validate(samples: &[(&str, &[Token])]) {\n    unimplemented!()\n}    \n\nfn main() {\n    let tokens_0 = [Token::PLUS, Token::MINUS, Token::PLUS];\n    let tokens_1 = [Token::MUL];\n    let samples: Vec<(&str, &[Token])> = vec![\n        ("a string", &tokens_0),\n        ("another string", &tokens_1),\n    ];\n    validate(&samples);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里对您的代码有两处更改。

\n\n

第一,此代码依赖于通过引用数组 ( [T; N]) 将其隐式强制转换为切片 ( )。这是类型 的&[T]声明所要求的。稍后在使用 时,通过传递对数组的引用来满足这一点,从而引发适当的强制转换。samplesVec<(&str, &[Token])>vec!

\n\n

Token第二,它在使用宏之前创建数组vec!,这保证了它们\xe2\x80\x99将足够活,可以从它创建的内部引用,并在完成Vec后保持这些引用有效。vec!在解决先前的类型不匹配之后,这是必要的。

\n\n
\n\n

附录

\n\n

或者,为了方便起见,您可能更喜欢使用 aVec而不是切片。考虑以下替代方案 [围栏]:

\n\n
enum Token {\n    PLUS,\n    MINUS,\n    MUL,\n}\n\nfn validate<T>(samples: &[(&str, T)]) where\n    T: AsRef<[Token]>\n{\n    let _: &[Token] = samples[0].1.as_ref();\n\n    unimplemented!()\n}    \n\nfn main() {\n    let samples: Vec<(&str, Vec<Token>)> = vec![\n        ("a string", vec![Token::PLUS, Token::MINUS, Token::PLUS]),\n        ("another string", vec![Token::MUL]),\n    ];\n    validate(&samples);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种情况下,AsRef<[Token]>元组第二个元素上的绑定接受您可以从中获取 a 的任何类型&[Token],提供as_ref()返回预期引用的方法。Vec<Token>就是这种类型的一个例子。

\n\n
\n\n

[1] \xe2\x80\x9cRust 目前不支持超过数组类型大小的泛型。\xe2\x80\x9d [ source ]

\n