Jaki jest najlepszy sposób tworzenia i używania struktury z tylko jedną instancją w systemie? Tak, jest to konieczne, jest to podsystem OpenGL, a tworzenie wielu kopii tego i przekazywanie go wszędzie wprowadziłoby zamieszanie, a nie złagodziło.
Singleton musi być tak wydajny, jak to tylko możliwe. Nie wydaje się możliwe przechowywanie dowolnego obiektu w obszarze statycznym, ponieważ zawiera on a Vec
z destruktorem. Drugą opcją jest przechowywanie (niebezpiecznego) wskaźnika w obszarze statycznym, wskazującego na singleton przydzielony do sterty. Jaki jest najwygodniejszy i najbezpieczniejszy sposób, aby to zrobić, zachowując zwięzłą składnię.
Odpowiedzi:
Brak odpowiedzi
Ogólnie unikaj stanu globalnego. Zamiast tego skonstruuj obiekt gdzieś wcześnie (być może w
main
), a następnie przekaż zmienne odniesienia do tego obiektu w miejsca, które tego potrzebują. Zwykle sprawia to, że twój kod jest łatwiejszy do rozważenia i nie wymaga tak dużego pochylania się od tyłu.Przyjrzyj się sobie uważnie w lustrze, zanim zdecydujesz, że chcesz, aby zmienne globalne były zmienne. Są rzadkie przypadki, w których jest to przydatne, dlatego warto wiedzieć, jak to zrobić.
Nadal chcesz zrobić ...?
Używanie lazy-static
Leniwy-statyczne paka może zabrać niektóre znoju ręcznego tworzenia pojedyncza. Oto globalny zmienny wektor:
Jeśli usuniesz,
Mutex
to masz globalny singleton bez żadnej zmienności.Możesz także użyć a
RwLock
zamiast a,Mutex
aby zezwolić wielu jednoczesnym czytnikom.Korzystanie z Once_cell
Once_cell paka może zabrać niektóre znoju ręcznego tworzenia pojedyncza. Oto globalny zmienny wektor:
Jeśli usuniesz,
Mutex
to masz globalny singleton bez żadnej zmienności.Możesz także użyć a
RwLock
zamiast a,Mutex
aby zezwolić wielu jednoczesnym czytnikom.Szczególny przypadek: atomika
Jeśli chcesz śledzić tylko wartość całkowitą, możesz bezpośrednio użyć atomowej :
Ręczna, wolna od zależności implementacja
Jest to w dużej mierze zaczerpnięte z implementacji Rusta 1.0
stdin
z kilkoma poprawkami dla współczesnego Rusta. Warto również przyjrzeć się nowoczesnej implementacjiio::Lazy
. Skomentowałem w tekście, co robi każda linia.To drukuje:
Ten kod kompiluje się z Rust 1.42.0. Rzeczywiste implementacje
Stdin
używają pewnych niestabilnych funkcji, aby spróbować zwolnić przydzieloną pamięć, czego ten kod nie robi.Naprawdę, to prawdopodobnie chcesz, aby
SingletonReader
wdrożyćDeref
iDerefMut
tak nie trzeba kłuć do obiektu i zablokować go samodzielnie.Cała ta praca jest tym, co robi dla ciebie lazy-static lub once_cell.
Znaczenie słowa „globalny”
Pamiętaj, że nadal możesz używać normalnego zakresu Rusta i prywatności na poziomie modułu, aby kontrolować dostęp do zmiennej
static
lublazy_static
. Oznacza to, że możesz zadeklarować go w module lub nawet wewnątrz funkcji i nie będzie on dostępny poza tym modułem / funkcją. Jest to dobre do kontrolowania dostępu:Jednak zmienna jest nadal globalna, ponieważ istnieje jej jedno wystąpienie, które istnieje w całym programie.
źródło
void *
które są następnie przekazywane z powrotem do metod każdego modułu. Jest to typowy wzorzec rozszerzenia dla kodu C. Jeśli aplikacja na to nie pozwala i nie możesz tego zmienić, to tak, singleton może być dobrym rozwiązaniem.lazy_static
przykład w Rust 1.24.1 i działa dokładnie.external static
Nigdzie tu nie ma . Być może musisz sprawdzić rzeczy po swojej stronie, aby upewnić się, że w pełni zrozumiałeś odpowiedź.Użyj SpinLock, aby uzyskać dostęp globalny.
Jeśli chcesz zmieniać stan (NIE Singleton), zobacz Czego nie robić w Rust, aby uzyskać więcej opisów.
Mam nadzieję, że to pomocne.
źródło
Odpowiadając na moje zduplikowane pytanie .
Cargo.toml:
Katalog główny skrzynki (lib.rs):
Inicjalizacja (nie ma potrzeby stosowania niebezpiecznego bloku):
EDYTOWAĆ:
Udało się go rozwiązać za pomocą Once_cell, który nie potrzebuje makra.
Cargo.toml:
square.rs:
źródło
lazy_static
i nowszymionce_cell
. Celem oznaczania rzeczy jako duplikatów w SO jest uniknięcie nadmiarowych informacji.