如何将带有类型参数的结构作为函数参数传递? [英] How do I pass a struct with type parameters as a function argument?

查看:51
本文介绍了如何将带有类型参数的结构作为函数参数传递?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何传递 EcsClient 带有签名 implEcsClient<P, D>其中 P:ProvideAwsCredentials,D:DispatchSignedRequest 到一个函数作为 Rust 中的引用?我的尝试是这样的:

How do I pass an instance of EcsClient with the signature impl<P, D> EcsClient<P, D> where P: ProvideAwsCredentials, D: DispatchSignedRequest to a function as a reference in Rust? My attempt is thus:

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

我尝试的解决方法是这样的:

My attempted fix for this is such:

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`

这感觉就像一个兔子洞,我不应该进去.

This feels like a rabbit hole I shouldn't be going down.

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

I've also tried changing the function signature to accept generics, however the EcsClient is a struct not a trait. Googling doesn't provide much help because I don't know the correct terms to search for.

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

This question seems to imply that I should be able to declare a function like fn my_func(client: &EcsClient) { ... } and it will work, so why doesn't the above example?

推荐答案

问题在于 EcsClient 不是类型,而是构建类型的蓝图(也称为类型构造函数").

The problem is that EcsClient is not a type, it's a blueprint to build a type (also known as "type constructor").

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

As a result, you cannot use just EcsClient when a type is required, be it in functions or for struct members; instead, each time, you must use it to build a type by specifying its generic parameters.

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

Thus, the first step is to introduce the type parameters:

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

然而,现在编译器会抱怨 PD 的约束不够:EcsClient 只接受一种非常特殊的 PD!

Now, however, the compiler will complain that the P and D are insufficiently constrained: EcsClient only accept a very specific kind of P and D!

因此,下一步是在 EcsClientD 的定义中查找为 PD 指定的边界应用它们.此时只是复制/粘贴:

The next step, thus, is to look-up the bounds that are specified for P and D in the definition of EcsClient and apply them. It's just copy/paste at this point:

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

然后你就是金色的.

如果您需要 PD更多功能来实现此特定功能,请随时通过使用 <添加更多边界来充分约束它们代码>+:

If you need more capabilities of P or D for this specific function, feel free to constrain them adequately by adding more bounds using +:

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

<小时>

如果你想知道为什么 Rust 选择让你重复 PD 的边界,因为它可以完美地推断它们,那是因为它关心你.更具体地说,它在 6 个月后关心你,以及下一个维护者.因此,采取一次编写并阅读多次的立场,它会迫使您复制边界,以便以后您不必怀疑它们是什么,并在用于痛苦地聚合所有部分的每个类型/函数中递归向下钻取.在 Rust 中,下次您阅读该函数时,您将获得所有信息.


If you wonder why Rust chose to have you repeat the bounds for P and D when it could perfectly infer them, it's because it cares about you. More specifically, it cares about you 6 months from now, and the next maintainer to come. So, taking the stance that you write once and read many, it forces you to copy the bounds so that later you don't have to wonder what they are, and drill down recursively in each type/function used to painfully aggregate all the pieces. In Rust, the next time you read the function, you'll have all the information right there.

这篇关于如何将带有类型参数的结构作为函数参数传递?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆