如何将带有类型参数的结构作为函数参数传递?

时间:2017-02-06 09:56:19

标签: rust rusoto

如何将带有签名impl<P, D> EcsClient<P, D> where P: ProvideAwsCredentials, D: DispatchSignedRequest的{​​{3}}实例传递给作为Rust中引用的函数?因此我的尝试是:

extern crate rusoto;

use std::default::Default;

use rusoto::{ DefaultCredentialsProvider, Region };
use rusoto::ecs::{ EcsClient };
use rusoto::default_tls_client;

fn get_task_definition_revisions(client: &EcsClient) {
    // Use EscClient instance here
}

fn main() {
    let provider = DefaultCredentialsProvider::new().unwrap();
    let client = EcsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1).unwrap();

    get_task_definition_revisions(&client);

}

这给了我以下错误:

error[E0243]: wrong number of type arguments: expected 2, found 0
 --> src/main.rs:9:43
  |
9 | fn get_task_definition_revisions(client: &EcsClient) {
  |                                           ^^^^^^^^^ expected 2 type arguments

我试图解决这个问题是这样的:

extern crate rusoto;

use std::default::Default;

use rusoto::{
    DefaultCredentialsProvider,
    Region,
    ProvideAwsCredentials,
    DispatchSignedRequest
};
use rusoto::ecs::{ EcsClient, ListTaskDefinitionsRequest };
use rusoto::default_tls_client;

fn get_task_definition_revisions(client: &EcsClient<ProvideAwsCredentials, DispatchSignedRequest>) {
    // Use EcsClient instance here
}

fn main() {
    let provider = DefaultCredentialsProvider::new().unwrap();
    let client = EcsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1);

    get_task_definition_revisions(&client);
}

这给了我:

error[E0277]: the trait bound `rusoto::ProvideAwsCredentials + 'static: std::marker::Sized` is not satisfied
  --> src/main.rs:14:1
   |
14 |   fn get_task_definition_revisions(client: &EcsClient<P, D>) {
   |  _^ starting here...
15 | |  let defs = client.list_task_definitions(&ListTaskDefinitionsRequest {
16 | |      family_prefix: None,
17 | |      max_results: None,
18 | |      next_token: None,
19 | |      sort: None,
20 | |      status: Some("ACTIVE".to_string()),
21 | |  });
22 | | }
   | |_^ ...ending here: the trait `std::marker::Sized` is not implemented for `rusoto::ProvideAwsCredentials + 'static`
   |
   = note: `rusoto::ProvideAwsCredentials + 'static` does not have a constant size known at compile-time
   = note: required by `rusoto::ecs::EcsClient`

error[E0277]: the trait bound `rusoto::DispatchSignedRequest + 'static: std::marker::Sized` is not satisfied
  --> src/main.rs:14:1
   |
14 |   fn get_task_definition_revisions(client: &EcsClient<P, D>) {
   |  _^ starting here...
15 | |  let defs = client.list_task_definitions(&ListTaskDefinitionsRequest {
16 | |      family_prefix: None,
17 | |      max_results: None,
18 | |      next_token: None,
19 | |      sort: None,
20 | |      status: Some("ACTIVE".to_string()),
21 | |  });
22 | | }
   | |_^ ...ending here: the trait `std::marker::Sized` is not implemented for `rusoto::DispatchSignedRequest + 'static`
   |
   = note: `rusoto::DispatchSignedRequest + 'static` does not have a constant size known at compile-time
   = note: required by `rusoto::ecs::EcsClient`

这感觉就像一个兔子洞,我不应该沮丧。

我也尝试更改函数签名以接受泛型,但EcsClient是结构而不是特征。谷歌搜索并没有提供太多帮助,因为我不知道要搜索的正确术语。

EcsClient似乎暗示我应该能够声明像fn my_func(client: &EcsClient) { ... }这样的函数并且它会起作用,那为什么不是上面的例子?

2 个答案:

答案 0 :(得分:3)

问题在于EcsClient不是类型,它是构建类型的蓝图(也称为&#34;类型构造函数&#34;)。

因此,当需要类型时,无论是在函数中还是在struct成员中,都不能使用 EcsClient;相反,每次都必须通过指定其通用参数来使用它来构建类型。

因此,第一步是引入类型参数:

fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>) {}

然而,现在,编译器会抱怨PD受到的限制不足:EcsClient只接受非常具体的PD }!

因此,下一步是在P的定义中查找为DEcsClient指定的边界并应用它们。它只是在这一点上复制/粘贴:

fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
    where P: ProvideAwsCredentials,
          D: DispatchSignedRequest
{
}

然后你就变得金黄了。

如果您需要此PD更多功能,请随意使用+添加更多边界来充分约束它们:< / p>

fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
    where P: ProvideAwsCredentials + 'static,
          D: DispatchSignedRequest
{
}

如果你想知道为什么Rust选择让你重复PD的界限,当它可以完美地推断它们时,它是因为它关心你。更具体地说,从现在起6个月后它会关心你,并且是下一个维护者。因此,采取一次写入并阅读多次的立场,它会强制您复制边界,以便以后您不必怀疑它们是什么,并在每个类型/函数中递归地向下钻取,以便痛苦地汇总所有碎片。在Rust中,下次阅读该功能时,您将获得所有信息。

答案 1 :(得分:1)

我错误地理解了语法。似乎PD是占位符,就像T一样。我需要指定这些类型是什么,所以签名现在看起来像这样:

fn get_task_definition_revisions<P: ProvideAwsCredentials, D: DispatchSignedRequest>(client: &EcsClient<P, D>) {
    ...
}

我不在函数体中使用PD,但必须声明它们。

完整示例现在看起来像:

extern crate rusoto;

use std::default::Default;

use rusoto::{
    DefaultCredentialsProvider,
    Region,
    ProvideAwsCredentials,
    DispatchSignedRequest
};
use rusoto::ecs::{ StringList, EcsClient, ListTaskDefinitionsRequest };
use rusoto::default_tls_client;

fn get_task_definition_revisions<P: ProvideAwsCredentials, D: DispatchSignedRequest>(client: &EcsClient<P, D>) {
    let res = client.list_task_definitions(&ListTaskDefinitionsRequest {
        family_prefix: None,
        max_results: None,
        next_token: None,
        sort: None,
        status: Some("ACTIVE".to_string()),
    });

    // ...
}

fn main() {
    let provider = DefaultCredentialsProvider::new().unwrap();
    let client = EcsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1);

    get_task_definition_revisions(&client);
}

我仍然不完全确定为什么这样做或需要,但我希望这个答案可以帮助别人。