Ir para o conteúdo

Strings ​

Texto é bytes, e eles são UTF-8 ​

Uma string é texto UTF-8 imutável com semântica de valor. Um char é um Unicode scalar value.

talor
let s = "héllo";
s.len()             // 6: len counts bytes
s.char_at(0)        // 'h': the char whose encoding holds byte 0
s[1]                // 0xC3: the byte itself, a u8, for code that walks encodings
for c in s {        // one iteration per character, decoded
    println(`${c}`);
}

Um literal char guarda um scalar value, qualquer que seja a largura dele codificado: 'é' as i64 é 233, e c.to_string() codifica um char de volta nos bytes de onde ele veio.

Literais e escapes:

talor
let a = "line\nand \t tab, \"quoted\", \0 and \u{1F600}";
let c = '\n';

Templates: o único mecanismo de formatação ​

talor
let s = `${name} has ${count} items`;

Cada ${...} guarda uma expressão de um tipo primitivo ou de um tipo que implementa Display; as partes são concatenadas em uma string. Não existem placeholders {} nem format!: este é o único mecanismo do Core.

A interpolação não é um formatador: ela responde seis dígitos significativos e passa para notação de expoente por conta própria, então ${123456789.123} é 1.23457e+08. Quando o texto importa, std.fmt diz quantos dígitos e em qual base: fmt.float(v, 2) para ponto fixo, fmt.shortest(v) para o texto mais curto que é lido de volta como o mesmo double, fmt.base(v, radix) / fmt.hex, fmt.oct, fmt.bin, e fmt.group(text, 3, ",").

Operações ​

OperaçãoSignificado
s + tconcatenação
s == t, s != tcomparação de conteúdo
s.len()bytes
s.char_at(i)o char cuja codificação contém o byte i; '\0' depois do fim
s[i]o byte em i, um u8; depois do fim dá panic, como xs[i]. Um u8 não é um char, então s[i] == 'a' é recusado
s.slice(a, b)o texto do byte a ao byte b; uma posição depois do fim é o fim, uma negativa conta para trás a partir do fim, e a igual a b ou depois dele é ""
s.starts_with(t)teste de prefixo
s.to_i64(), s.to_f64()Option do número lido
for c in spercorre os caracteres, decodificados

Uma posição dentro de um caractere significa o início desse caractere, em char_at e em slice: "naïve".slice(0, 3) é "na" e "naïve".char_at(3) é 'ï'. Nenhum dos dois dá panic, e um slice é sempre UTF-8.

Uma string tem reference counting feito pelo runtime: uma cópia faz retain e um release decrementa, o que o programa não consegue observar, porque strings são imutáveis. Um literal é uma constante com contagem imortal. .clone() é uma cópia profunda.

Ler, construir, e bytes que não são texto ​

std.str.Cursor lê uma string um caractere por vez, e as posições dele são sempre inícios de caractere: next() responde o caractere e passa por ele, peek() responde e fica, os dois None no fim; eat(ch) passa por ch quando ele é o próximo; at() é o offset, e since(m) é o texto de m até aqui. std.str.Builder monta uma string por append, com push(s), push_char(c) e to_string(): ele é a resposta a s = s + piece em um loop, que copia tudo o que já foi escrito a cada pedaço.

std.bytes guarda bytes que não são texto: um buffer é um Array<u8>, bytes.of(s) copia os bytes de uma string, e bytes.text(buf, at, len) é o único caminho de volta para uma string, um Err que nomeia o offset quando os bytes não são UTF-8. fs.read_file(p) lê um arquivo como texto verificado, e fs.read(p) como bytes.

talor
use std.str.{Cursor, Builder};
use std.bytes;

fn words(src: string): Array<string> {
    let out: Array<string> = [];
    let c = Cursor.of(src);
    let going = true;
    while going {
        while c.eat(' ') { }
        let start = c.at();
        let more = true;
        while more {
            match c.peek() {
                Some(ch) => { if ch == ' ' { more = false; } else { c.next(); } }
                None => { more = false; going = false; }
            }
        }
        if c.at() > start { out.push(c.since(start)); }
    }
    out
}

fn main(): i32 {
    let b = Builder.new();
    for w in words("  one sentence   in  words ") { b.push(w); b.push_char('|'); }
    println(b.to_string());

    let raw = bytes.of("ok");
    raw.push(255);
    match bytes.text(raw, 0, raw.len()) {
        Ok(t) => println(t),
        Err(e) => println(`not text: ${e.message()}`),
    }
    0
}

Talor v0.1.0 - Publicado sob a licença MIT OR Apache-2.0.