Negative views on Rust ( not mine! )

That first approach is also how Rust may be doing it; it just so happens that the compiler / linker may be laying out all these strings together. In C:

static char const * const msgs[] = {
    [ERR1] = "long message for err1",
    [ERR2] = "but message for err2 can be longer",
    [ERR3] = "or message for err3 can be short"
};

is the same as (modulo string ordering):

static char const msg1[] = "long message for err1" /* + \0 */;
static char const msg2[] = "but message for err2 can be longer";

static char const * const msgs[] = {
    [ERR1] = &msg1,
    [ERR2] = &msg2,
    …
};

That means that msg1 and msg2 (and so on) are perfectly allowed to to be laid out contiguously in static / global memory:

// by the linker:
static uint8_t const GLOBAL_RO_MEMORY[] = {
    …

    'l', 'o', 'n', 'g', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e',
    ' ', 'f', 'o', 'r', ' ', 'e', 'r', 'r', '1', '\0',

    'b', 'u', 't', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', ' ',
    'f', 'o', 'r', ' ', 'e', 'r', 'r', '2', ' ', 'c', 'a', 'n', ' ',
    'b', 'e', ' ', 'l', 'o', 'n', 'g', 'e', 'r', '\0',

    …
};

And it turns out Rust may do the same thing, but with the big difference that Rust's strings are not null-terminated, so a C-String "scanning" that would start at long message… would simply not stop until reaching a null byte arbitrarily far away in memory, hence "exposing" other officially-unrelated-even-if-laid-out-contiguously-by-the-linker read-only memory, such as the other language strings.

To further prove my point:

6 Likes