Qual é a melhor maneira de criar e usar uma estrutura com apenas uma instanciação no sistema? Sim, isso é necessário, é o subsistema OpenGL, e fazer várias cópias disso e distribuí-lo em todos os lugares aumentaria a confusão, em vez de aliviá-la.
O singleton precisa ser o mais eficiente possível. Não parece possível armazenar um objeto arbitrário na área estática, pois contém um Vec
com um destruidor. A segunda opção é armazenar um ponteiro (não seguro) na área estática, apontando para um singleton alocado no heap. Qual é a maneira mais conveniente e segura de fazer isso, mantendo a sintaxe concisa.
Respostas:
Resposta sem resposta
Evite o estado global em geral. Em vez disso, construa o objeto em algum lugar no início (talvez em
main
) e, em seguida, transmita referências mutáveis a esse objeto nos lugares que precisam dele. Isso geralmente tornará seu código mais fácil de raciocinar e não exigirá muito esforço para retroceder.Olhe bem para si mesmo no espelho antes de decidir que deseja variáveis globais mutáveis. Existem raros casos em que é útil, por isso vale a pena saber como fazer.
Ainda quer fazer um ...?
Usando lazy-static
O engradado estático preguiçoso pode eliminar parte do trabalho enfadonho de criar manualmente um único. Aqui está um vetor mutável global:
Se você remover o
Mutex
, terá um singleton global sem qualquer mutabilidade.Você também pode usar um em
RwLock
vez de umMutex
para permitir vários leitores simultâneos.Usando once_cell
A caixa once_cell pode tirar um pouco do trabalho enfadonho de criar manualmente um singleton. Aqui está um vetor mutável global:
Se você remover o
Mutex
, terá um singleton global sem qualquer mutabilidade.Você também pode usar um em
RwLock
vez de umMutex
para permitir vários leitores simultâneos.Um caso especial: atômica
Se você só precisa rastrear um valor inteiro, pode usar diretamente um atômico :
Implementação manual, livre de dependência
Isso é muito limitado pela implementação do Rust 1.0
stdin
com alguns ajustes para o Rust moderno. Você também deve olhar para a implementação moderna deio::Lazy
. Eu comentei inline com o que cada linha faz.Isso imprime:
Este código é compilado com Rust 1.42.0. As implementações reais de
Stdin
usam alguns recursos instáveis para tentar liberar a memória alocada, o que este código não faz.Na verdade, você provavelmente gostaria de fazer um
SingletonReader
implementoDeref
e,DerefMut
portanto, não precisou cutucar o objeto e travá-lo sozinho.Todo esse trabalho é o que lazy-static ou once_cell fazem por você.
O significado de "global"
Observe que você ainda pode usar o escopo normal do Rust e a privacidade no nível do módulo para controlar o acesso a uma variável
static
oulazy_static
. Isso significa que você pode declará-lo em um módulo ou mesmo dentro de uma função e não estará acessível fora desse módulo / função. Isso é bom para controlar o acesso:No entanto, a variável ainda é global porque há uma instância dela que existe em todo o programa.
fonte
void *
que são então passados de volta para os métodos de cada módulo. Este é um padrão de extensão típico para código C. Se o aplicativo não permitir isso e você não puder alterá-lo, sim, um singleton pode ser uma boa solução.lazy_static
exemplo em Rust 1.24.1 e funciona exatamente. Não há nenhumexternal static
lugar aqui. Talvez você precise verificar as coisas do seu lado para ter certeza de que entendeu a resposta completamente.Use SpinLock para acesso global.
Se você quiser um estado mutável (NÃO Singleton), consulte O que não fazer no Rust para obter mais descrições.
Espero que seja útil.
fonte
Respondendo minha própria pergunta duplicada .
Cargo.toml:
Raiz da caixa (lib.rs):
Inicialização (sem necessidade de bloqueio inseguro):
EDITAR:
Consegui resolver com once_cell, que não precisa de macro.
Cargo.toml:
square.rs:
fonte
lazy_static
e as mais recentesonce_cell
. O objetivo de marcar coisas como duplicatas no SO é evitar informações redundantes.