Hoje encontrei aqui uma sintaxe um tanto estranha - where ()
:
https://github.com/binator/self/tree/80ba2ade?tab=readme-ov-file#example
fn hex_primary<Stream, Context>(stream: Stream) -> Parsed<u8, Stream, Context>
where
(): IntRadixParse<Stream, Context, u8>,
{
uint_radix(2, Radix::HEX).parse(stream)
}
Para mim parece "limitado ao tipo unitário (também conhecido como tupla vazia )", mas não consigo entender. Um tipo unitário não implementa todas as características por padrão, certo? Infelizmente, a documentação oficial é muito vaga e não é completa o suficiente (ao mesmo tempo em que é excessivamente prolixa), e não consegui encontrar nada relacionado nela.
A cláusula RFC for original where
também menciona essa sintaxe, mas sem explicação adequada:
https://rust-lang.github.io/rfcs/0135-where.html#alternatives
fn increment<T>(c: T) -> T
where () : Add<int,T,T>
{
1 + c
}
Mas além disso, eu sei que tais limites podem ser especificados não apenas em genéricos de traits.
Então o que é, quando é usado, por que é necessário e quais problemas ele resolve?
No trecho de código, a
where
cláusula é usada para restringir as restrições genéricas. Em vez de definir todas as restrições,(): IntRadixParse<Stream, Context, u8>
é usada, o que significa que qualquer tipoStream
eContext
têm, eles devem seguir as restrições deIntRadixParse
.O traço
IntRadixParse
éNota: Ele usa o recurso de alias de traço instável
Então, para escrever a função sem a estranha sintaxe de restrição de unidade, seria algo como
Nota: Na função
Token
foi substituído poru8
Outro exemplo :
(): IntRadixParse<Stream, Context, u8>
realmente é um limite no tipo de unidade. Funciona porque o alias de trait 1 é definido assim:Observe especialmente a característica ausente antes de
where
, não há característica, então este é um alias para nenhuma característica, dadas as condições.Cada tipo preenche "implementa um conjunto vazio de características", então a única coisa que resta a ser provada pelo compilador são os limites. Então, resumindo, como
Self
não é referenciado e não há nenhuma característica para ele preencher, em vez de unit()
você pode escrever qualquer tipo lá. Quando o tipo não importa, os programadores Rust geralmente usam unit.Isso torna os aliases de características úteis para abreviar um monte de limites, como explicado na resposta de Timsib Adnap