Pisząc wywołania zwrotne dla interfejsów ogólnych, może być przydatne dla nich zdefiniowanie własnych danych lokalnych, które są odpowiedzialne za tworzenie i uzyskiwanie dostępu.Wygodny "Opcja <Box<Any>>" dostęp, gdy sukces jest zapewniony?
W CI będzie po prostu użyć void wskaźnik, C-podobny przykład:
struct SomeTool {
int type;
void *custom_data;
};
void invoke(SomeTool *tool) {
StructOnlyForThisTool *data = malloc(sizeof(*data));
/* ... fill in the data ... */
tool.custom_data = custom_data;
}
void execute(SomeTool *tool) {
StructOnlyForThisTool *data = tool.custom_data;
if (data.foo_bar) { /* do something */ }
}
Pisząc coś podobnego w Rust, zastępując void *
z Option<Box<Any>>
, jednak jestem stwierdzenia, że dostęp do danych jest nieracjonalnie gadatliwy, np:
struct SomeTool {
type: i32,
custom_data: Option<Box<Any>>,
};
fn invoke(tool: &mut SomeTool) {
let data = StructOnlyForThisTool { /* my custom data */ }
/* ... fill in the data ... */
tool.custom_data = Some(Box::new(custom_data));
}
fn execute(tool: &mut SomeTool) {
let data = tool.custom_data.as_ref().unwrap().downcast_ref::<StructOnlyForThisTool>().unwrap();
if data.foo_bar { /* do something */ }
}
jest jedna linia o której chciałbym, aby móc pisać w sposób bardziej zwarty:
tool.custom_data.as_ref().unwrap().downcast_ref::<StructOnlyForThisTool>().unwrap()
tool.custom_data.as_ref().unwrap().downcast_mut::<StructOnlyForThisTool>().unwrap()
Chociaż każda metoda ma sens, na własną rękę, w praktyce to nie jest coś, co chcę napisać w całym kodzie bazy, a nie coś, co zamierzam chcesz często pisać lub łatwo zapamiętać.
Umownie, zastosowania rozpakować tutaj nie są niebezpieczne, ponieważ:
- Chociaż tylko niektóre narzędzia definiowania niestandardowych danych, te, które zawsze zdefiniować.
- Gdy dane są ustawione, zgodnie z konwencją narzędzie zawsze ustawia własne dane. Nie ma więc szansy na zło danych.
- Za każdym razem, gdy konwencje te nie są przestrzegane, jest to błąd i powinien panikować.
Biorąc pod uwagę te konwencje i zakładając, że dostęp do danych niestandardowych z narzędzia jest często wykonywany - jaki byłby dobry sposób na uproszczenie tego wyrażenia?
Możliwe opcje:
- Zdjąć
Option
, wystarczy użyćBox<Any>
zBox::new(())
reprezentującyNone
więc dostęp można uprościć trochę. - Użyj makra lub funkcji, aby ukryć szczegółowość - przejście w trybie
Option<Box<Any>>
: zadziała oczywiście, ale wolisz - nie będzie używane jako ostateczność. - Dodaj cechę do
Option<Box<Any>>
, która udostępnia taką metodę, jaktool.custom_data.unwrap_box::<StructOnlyForThisTool>()
z dopasowaniemunwrap_box_mut
.
Update 1): ponieważ tym pytaniem punkt nie obejmuje wydaje się istotne. Może istnieć wiele funkcji zwrotnych, takich jak execute
, które muszą mieć dostęp do custom_data
. W tamtym czasie nie sądziłem, że to ważne, aby zwrócić uwagę.
Aktualizacja 2): Opakowanie to w zależności, która zabierze tool
nie jest możliwe, ponieważ kontroler pożyczyć następnie zapobiega dalszemu dostęp do członków tool
dopóki zmienna obsada wykracza poza zakres, znalazłem tylko niezawodny sposób do zrobienia to było napisanie makra.
Czy jest jakiś powód, dla którego nie używa się tylko zamknięć? Zamknięcia są tam, aby powstrzymać nas od konieczności użycia wskaźnika funkcji + pary wskaźników danych. Tak jak plasterki są po to, aby powstrzymać nas przed potrzebą wskaźnika danych + pary długości. –
Co powiesz na tworzenie metod dostępu do 'SomeTool'? 'custom_data()' i 'custom_data_mut()'. –
@ JorgeIsraelPeña: Ta sama reakcja tutaj; Zastanawiam się, czy czegoś brakuje, bo wydaje się oczywiste, że należy utworzyć funkcję, a nie kopiować/wklejać :( –