Можно ли вернуть тип реализации из признака? [Дубликат]

Посмотрите на этот пример:

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:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/

8
задан GGalizzi 11 January 2015 в 22:35
поделиться

2 ответа

Как вы заметили, downcasting работает только с Any признаком, и да, он поддерживает только данные 'static. Вы можете найти недавнюю дискуссию о том, почему здесь здесь . В принципе, реализовать отражение для ссылок на произвольные времена жизни сложно.

Также невозможно (на данный момент, по крайней мере) скомбинировать Any с вашим пользовательским признаком. Однако недавно была создана библиотека macro для автоматической реализации Any для вашей черты. Вы также можете найти здесь обсуждение .

8
ответ дан Vladimir Matveev 1 September 2018 в 00:50
поделиться

Это не проблема, зависящая от ржавчины, хотя словарь может немного отличаться. Идеальный способ решить такую ​​проблему, а не только с чертами 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 к самому признаку.

2
ответ дан trentcl 1 September 2018 в 00:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: