Посмотрите на этот пример:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,$http) {
var getJoke = function(){
return $http.get('http://api.icndb.com/jokes/random').then(function(res){
return res.data.value;
});
}
getJoke().then(function(res) {
console.log(res.joke);
});
});
Как вы можете видеть, getJoke
возвращает разрешенное обещание (оно разрешено при возврате res.data.value
). Таким образом, вы ждете, пока запрос $ http.get не будет завершен, а затем выполнится console.log (res.joke) (как обычный асинхронный поток).
Это plnkr:
Как вы заметили, downcasting работает только с Any
признаком, и да, он поддерживает только данные 'static
. Вы можете найти недавнюю дискуссию о том, почему здесь здесь . В принципе, реализовать отражение для ссылок на произвольные времена жизни сложно.
Также невозможно (на данный момент, по крайней мере) скомбинировать Any
с вашим пользовательским признаком. Однако недавно была создана библиотека macro для автоматической реализации Any
для вашей черты. Вы также можете найти здесь обсуждение .
Это не проблема, зависящая от ржавчины, хотя словарь может немного отличаться. Идеальный способ решить такую проблему, а не только с чертами Rust, но на любом языке, заключается в добавлении желаемого поведения (foo_method
в вашем примере) к абстрактному интерфейсу (Trait
):
trait Trait {
fn trait_method(&self);
fn foo_method(&self) {} // does nothing by default
}
struct Foo;
impl Trait for Foo {
fn trait_method(&self) {
println!("In trait_method of Foo");
}
fn foo_method(&self) { // override default behavior
println!("In foo_method");
}
}
struct Bar;
impl Trait for Bar {
fn trait_method(&self) {
println!("In trait_method of Bar");
}
}
fn main() {
let vec: Vec<Box<Trait>> = vec![Box::new(Foo), Box::new(Bar)];
for e in &vec {
e.trait_method();
e.foo_method();
}
}
В этом примере я поместил по умолчанию реализацию foo_method
в Trait
, которая ничего не делает, так что вам не нужно определять ее в каждом impl
, но только в том, он применяется. Вы должны действительно попытаться сделать описанную выше работу до того, как прибегнете к опусканию к конкретному типу, что имеет серьезные недостатки, которые почти исключают преимущества наличия объектов-признаков в первую очередь.
Тем не менее, есть случаи, когда может потребоваться понижение, и Rust действительно поддерживает его, хотя интерфейс немного неуклюж. Вы можете понизить &Trait
до &Foo
, добавив к &Any
промежуточную up :
use std::any::Any;
trait Trait {
fn as_any(&self) -> &Any;
}
struct Foo;
impl Trait for Foo {
fn as_any(&self) -> &Any {
self
}
}
fn downcast<T: Trait + 'static>(this: &Trait) -> Option<&T> {
this.as_any().downcast_ref()
}
as_any
должен быть методом в Trait
потому что ему нужен доступ к конкретному типу. Теперь вы можете попытаться вызвать методы Foo
в объекте объекта Trait
, подобном этому ( полный пример игровой площадки ):
if let Some(r) = downcast::<Foo>(trait_object_ref) {
r.foo_method();
}
Чтобы сделать эту работу, вам нужно укажите, какой тип вы ожидаете (::<Foo>
) и используйте if let
для обработки того, что происходит, когда ссылочный объект не является экземпляром Foo
. Вы не можете опустить объект объекта с конкретным типом, если не знаете точно , какой конкретный тип этого .
Но если вам когда-либо понадобится знать конкретный тип, объекты-объекты почти бесполезно! Вероятно, вы должны использовать enum
, чтобы вы получали ошибки времени компиляции, если вы опускаете какой-либо вариант обработки. Кроме того, вы не можете использовать Any
с структурами не 'static
, поэтому, если какой-либо Foo
может потребоваться содержать ссылку, эта конструкция является тупиковой. Лучшее решение, если вы можете это сделать, состоит в том, чтобы добавить foo_method
к самому признаку.