AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79591114
Accepted
Jordan_B
Jordan_B
Asked: 2025-04-25 00:43:24 +0800 CST2025-04-25 00:43:24 +0800 CST 2025-04-25 00:43:24 +0800 CST

Os genéricos constantes do Rust podem usar limites de características com uma desigualdade (por exemplo, N2 > N1)?

  • 772

Estou trabalhando em um projeto no qual estou construindo um tipo de vetor de bits em Rust e estou explorando se é possível restringir genéricos constantes usando limites de desigualdade.

Meu objetivo é projetar uma API que evite a verificação de limites em tempo de execução usando garantias em tempo de compilação baseadas em genéricos constantes, além de uma variante verificada em tempo de execução. Minha esperança é que essas funções sejam simples o suficiente para que o compilador possa embuti-las, de modo que seja uma abstração verdadeiramente de custo zero.

Aqui está um exemplo de código simplificado que demonstra o que estou tentando fazer. Este código não compila, mas mostra o tipo de restrição que desejo:

/// Idea: A function with multiple generic parameters where a 
/// trait bound is used to establish an ordering between them.
fn add_ordered<const N1: usize, const N2: usize>() -> usize 
where N2 > N1 {
    N1 + N2
}

fn main() {
    let n = add_ordered::<1, 2>();
    println!("{n}");
}

Se eu remover a cláusula where N2 > N1, o código será compilado, mas não manterá o tipo de invariante que estou tentando manter aqui (nesse caso, que N2 é maior que N2).

Minhas perguntas:

  • Existe atualmente uma maneira em Rust de escrever uma restrição genérica const como where N2 > N1?
  • Caso contrário, há alguma solução alternativa ou recurso de linguagem (noturno ou não) que permita algo semelhante?
  • Se realmente não há como fazer isso agora, há algum motivo para que não possa ser feito, além do fato de que simplesmente não foi feito? Isso poderia levar a uma possível RFC?

Pesquisei um pouco, mas não consegui encontrar muita coisa sobre isso. Quaisquer dicas ou explicações serão muito apreciadas. Obrigado!

rust
  • 2 2 respostas
  • 76 Views

2 respostas

  • Voted
  1. Best Answer
    ais523
    2025-04-25T01:22:24+08:002025-04-25T01:22:24+08:00

    Por que esse código não compila

    whereAs cláusulas em Rust participam do sistema de tipos – o compilador tenta provar em tempo de compilação que qualquer uso de um tipo, característica, método, etc. está em conformidade com suas wherecláusulas e rejeita o programa se isso não acontecer.

    Além de ser uma restrição sobre quando você pode usar o código, uma wherecláusula também fornece uma suposição que o compilador pode usar para provar que seu programa está correto. Por exemplo, esta função hipotética não compila:

    fn duplicate<T>(t: T) -> (T, T) {
        (t.clone(), t)
    }
    

    porque o compilador não consegue provar que os requisitos para a chamada t.clone()foram atendidos. No entanto, se você adicionar uma wherecláusula apropriada:

    fn duplicate<T>(t: T) -> (T, T) where T: Clone {
        (t.clone(), t)
    }
    

    então o código agora compila corretamente, porque o compilador pode usar a wherecláusula como uma prova de que a chamada t.clone()é válida.

    Um dos problemas básicos com o código que você está escrevendo é que, ao escrever uma wherecláusula, você está dizendo ao Rust para usá-la tanto para verificar se as chamadas para a função que você está definindo estão corretas quanto para verificar se as chamadas feitas pela função que você está definindo estão corretas. Atualmente, o Rust não suporta esse tipo de raciocínio sobre os valores possíveis para parâmetros constantes – por exemplo, se essa sintaxe fosse aceita, os programadores poderiam esperar usar a combinação das cláusulas where A > Be where B > Cpara atender a um where A > Crequisito, o que significaria que alguém precisaria implementar um código que pudesse raciocinar sobre as propriedades relevantes do >operador.

    Acontece que mesmo o caso mais simples desse tipo de coisa ainda não foi implementado: where N1 == N2também é rejeitado (com a mensagem de erro "restrições de igualdade ainda não são suportadas em wherecláusulas" e um link para o problema Rust #20041 ). Acontece que é difícil implementar até mesmo restrições relativamente simples no provador do sistema de tipos. Uma boa maneira de pensar sobre isso é que, para compilar um genérico, o compilador Rust precisa basicamente atuar como um provador de teoremas e produzir uma prova de que a compilação está correta; e quaisquer restrições adicionais que você possa impor a um genérico que possa participar da prova precisam ser implementadas como algo com que o provador de teoremas seja capaz de trabalhar, o que geralmente é bastante difícil (e provavelmente impossível no caso geral).

    A sintaxe específica que você estava tentando usar tem outro problema: após uma wherecláusula, o Rust normalmente espera ver o nome de um tipo e, em locais onde os tipos são esperados, <funcionam >como colchetes e correspondem uns aos outros. Portanto, o Rust interpreta o "the" >como um colchete de fechamento sem correspondência, em vez de um operador "maior que", e é por isso que a mensagem de erro que você recebe parece confusa e sem relação.

    Se você não precisa de uma prova de nível de tipo

    Todo esse problema acontece basicamente porque whereas cláusulas criam tanto uma obrigação de prova para o compilador provar algo durante a verificação de tipos, quanto uma suposição que o verificador de tipos pode usar para provar coisas. É bem possível que isso não seja exatamente o que você tinha em mente, e o requisito que você está tentando expressar seja, na verdade, apenas um requisito de segurança/correção, e não algo que participe das provas em nível de tipo – você quer que o compilador o verifique, mas não se importa que seja verificado especificamente no verificador de tipos ou que seja utilizável como uma suposição para provar outras coisas.

    Se você quiser que algo seja verificado em tempo de compilação, mas não necessariamente pelo verificador de tipos, não use a wherepalavra-chave : em vez disso, a palavra-chave mais geral para avaliação em tempo de compilação é const. Em versões recentes do Rust (1.79 ou posterior – a 1.79 foi lançada em 13 de junho de 2024, então algumas pessoas ainda usarão versões mais antigas), você pode escrever uma constasserção no corpo da sua função:

    fn add_ordered<const N1: usize, const N2: usize>() -> usize {
        const { assert!(N2 > N1) };
        N1 + N2
    }
    

    Isso será verificado em tempo de compilação e causará um erro em tempo de compilação se houver alguma chamada para add_orderedexist onde N2 > N1não for válido (a mensagem de erro informa a condição que falhou, a localização do const { … }bloco e a localização da chamada para a função). Ao contrário de uma wherecláusula, ela não participará da verificação de tipo; o compilador verifica isso N2 > N1porque você solicitou, mas não usa as informações para nenhum outro propósito além de produzir o erro em tempo de compilação se não for válido.

    Espero que isso seja bom o suficiente para o que você tinha em mente; não é bom o suficiente para provas de nível de tipo, mas ainda é bom o suficiente para, por exemplo, verificar uma invariante de solidez ou detectar usos acidentais sem sentido da API.

    • 7
  2. NyxCode
    2025-04-25T01:21:28+08:002025-04-25T01:21:28+08:00

    Infelizmente, isso não é possível no modo estável.
    Uma maneira de expressar isso no modo noturno seria:

    #![feature(generic_const_exprs)]
    
    fn add_ordered<const N1: usize, const N2: usize>() -> usize
    where
        [(); { N2 - N1 - 1 }]:,
    {
        N1 + N2
    }
    

    (sim, a sintaxe é estranha)

    No entanto, o recurso está incompleto e possivelmente falho.
    Além disso, pelo que ouvi, não há chance de que isso se estabilize tão cedo.

    • 5

relate perguntas

  • os braços de correspondência têm tipos incompatíveis esperados ao reutilizar a função dentro da correspondência

  • Conversão de tipo de ferrugem em uma instrução de correspondência

  • Como forçar o tipo de retorno de uma correspondência para ()?

  • enums de ferrugem em representações primitivas

  • Existe uma maneira de simplificar a correspondência diretamente para Ok("VAL") em Result<String, VarError>

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve