Этот вопрос действительно касается дизайна API, а не его влияния на реализацию. Реализация оказалась довольно многословной в основном из-за выбранного контракта: либо выведите значение, либо d ie. В этом контракте нет ничего плохого. Клиент, вызывающий эту функцию, никогда не обнаружит недействительные данные, поэтому это совершенно безопасно.
Хотя это может быть не лучшим вариантом для библиотечного кода. Библиотечному коду обычно не хватает контекста, и он не может правильно определить, является ли любое данное условие ошибки фатальным или нет. На этот вопрос клиентский код находится в гораздо лучшем положении для ответа.
Прежде чем перейти к изучению альтернатив, давайте переписываем исходный код более компактным способом, объединяя вызовы вместе, без явного присвоения каждого результата переменная:
fn decode_request(window: web_sys::Window) -> std::string::String {
window
.location()
.search().expect("no search exists")
.trim_start_matches('?')
.to_owned()
}
Я не знаком с web_sys
ящиком, так что здесь есть немного догадок. А именно, предположение, что window.location()
возвращает то же значение, что и document()
's location()
. Помимо цепочки вызовов, представленный код использует еще два изменения:
trim_start_matches()
передается символьный литерал вместо строкового литерала. Это позволяет получить оптимальный код, не полагаясь на оптимизатор компилятора, чтобы выяснить, что строка длиной 1 пытается найти отдельный символ. - Возвращаемое значение создается путем вызова
to_owned()
. Макрос format!
добавляет издержки и в итоге вызывает to_string()
. Хотя в этом случае это будет демонстрировать то же поведение, использование семантически более точной функции to_owned()
поможет вам обнаруживать ошибки во время компиляции (например, если вы случайно вернули 42.to_string()
).
Альтернативы
Более естественным способом реализации этой функции является возвращение либо значения, представляющего строку запроса, либо вообще никакого значения. Rust предоставляет тип Option
для удобного моделирования этого:
fn decode_request(window: web_sys::Window) -> Option<String> {
match window
.location()
.search() {
Ok(s) => Some(s.trim_start_matches('?').to_owned()),
_ => None,
}
}
Это позволяет клиенту функции принимать решения в зависимости от того, возвращает ли функция Some(s)
или None
. Это отображает все состояния ошибки в значение None
.
Если желательно сообщить причину сбоя вызывающей стороне, функция decode_request
может выбрать возврат Result
* Вместо этого значение 1042 *, например Result<String, wasm_bindgen::JsValue>
. При этом реализация может использовать оператор ?
, чтобы компактно распространять ошибки вызывающей стороне:
fn decode_request(window: web_sys::Window) -> Result<String, wasm_bindgen::JsValue> {
Ok(window
.location()
.search()?
.trim_start_matches('?')
.to_owned())
}