在 Rust 中是否有获取 C99 数组标识符或替代方案的方法?

6
我刚刚用C和Rust完成了一个关于计算元音字母数量的CodeWars kata。示例代码简单明了。可以使用数组作为快速映射。在这里,我将字符映射到逻辑值(0或1)。 C实现:
#include <stddef.h>
#include <stdint.h>

// :) This const array design looks smart & IMO-readable. Use of C99 feature.
const uint8_t areVowels[256]= {['a']=1, ['e']=1, ['i']=1, ['o']=1,  ['u']=1};

size_t get_count(const unsigned char *s)
{
  auto size_t count= 0;
  for (;*s!='\0';s++){
    count+= areVowels[*s];
  }
  return count;
}

Rust实现:

// :( Here is me pain. Unreadable, python3-generated array content.
const ARE_VOWELS:[u8;256]= [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];

fn get_count(s: &str) -> usize {
  let mut vowels_count: usize = 0;

  for c in s.bytes(){
      vowels_count+= ARE_VOWELS[c as usize] as usize;
  }
  
  return vowels_count;
}

我希望我能知道Rust中数组指示器的替代方法,这是C99的一个有用特性。在我的Rust代码中,同一字节数组的初始化更加麻烦。


1
Ian的回答很好。但是在我看来,这个问题的解决方案并不生疏。 - Netwave
3个回答

10

static mut 在这里是不必要的(而且也是一种不好的做法)。您可以将常量的值分配给能够在 const 上下文中被评估的代码块的值。

const ARE_VOWELS: [u8;256] = {
    let mut data = [0u8; 256];
    data['a' as usize] = 1;
    data['e' as usize] = 1;
    data['i' as usize] = 1;
    data['o' as usize] = 1;
    data['u' as usize] = 1;
    data
};

查看这个答案,使用宏使其更美观。


7

另一种方法是使用一个宏来提供您想要的语法,实际上制作一个通用目的的实现并不太难:

macro_rules! array {
    ($def:expr; $len:expr; $([$idx:expr]=$val:expr),* $(,)?) => { {
        let mut a = [$def; $len];
        $(a[$idx] = $val;)*
        a
    } }
}

let data = array![0; 256; ['a' as usize]=1, ['e' as usize]=1];

如果你喜欢的话,当然可以将as usize移到宏中。


2
哦,看这里,有一个箱子可以做到这一点甚至更多:array-lit - kmdreko
我真的很喜欢那个宏。它易于阅读和理解,我已经按照自己的方式重新编写了它。 - Sir

0

我发现了一些关于“mut static value runtime initialization”的(不安全的⇒有趣的)解决方法。

const VOWELS:&[u8;5]= b"aeiou";
static mut ARE_VOWELS:[u8;256]= [0;256];

fn init(){
    unsafe{
        let ptr: *mut u8= &mut ARE_VOWELS[0];
        for b in VOWELS{
            *(ptr.offset(*b as isize))= 1;
        }
    }
}

fn get_count(s: &str) -> usize {
    init();
    
    let mut vowels_count: usize = 0;

    for c in s.bytes(){
        unsafe{
            vowels_count+= ARE_VOWELS[c as usize] as usize;
        }
    }
  
    return vowels_count;
}

虽然我对这段代码的性能和可维护性表示严重怀疑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接