如何将具有类型参数的结构作为函数参数传递?
How do I pass a struct with type parameters as a function argument?
如何将带有签名 impl<P, D> EcsClient<P, D> where P: ProvideAwsCredentials, D: DispatchSignedRequest
的 EcsClient
的实例作为 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
是结构而不是特征。谷歌搜索没有提供太多帮助,因为我不知道要搜索的正确术语。
This question 似乎暗示我应该能够声明像 fn my_func(client: &EcsClient) { ... }
这样的函数并且它会起作用,那么为什么上面的例子不起作用?
我对语法的理解有误。 P
和 D
似乎是占位符,就像 T
一样。我需要指定 这些类型是什么 ,所以签名现在看起来像这样:
fn get_task_definition_revisions<P: ProvideAwsCredentials, D: DispatchSignedRequest>(client: &EcsClient<P, D>) {
...
}
我没有在函数体中使用P
或D
,但必须声明它们。
完整示例现在如下所示:
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);
}
我仍然不完全确定为什么这样做或需要这样做,但我希望这个答案对其他人有所帮助。
问题是 EcsClient
不是类型,它是构建类型的蓝图(也称为 "type constructor")。
因此,当需要类型时,您不能使用 just EcsClient
,无论是在函数中还是对于结构成员;相反,每次都必须通过指定其通用参数来使用它来构建类型。
因此,第一步是引入类型参数:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>) {}
然而,现在编译器会抱怨 P
和 D
没有足够的约束:EcsClient
只接受一种非常特殊的 P
和 D
!
因此,下一步是 look-up 在 EcsClient
的定义中为 P
和 D
指定的边界并应用它们。此时只有 copy/paste:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
where P: ProvideAwsCredentials,
D: DispatchSignedRequest
{
}
然后你就是金色的。
如果您需要 更多 P
或 D
的功能来实现此特定功能,请随时通过使用 [= 添加更多边界来充分限制它们25=]:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
where P: ProvideAwsCredentials + 'static,
D: DispatchSignedRequest
{
}
如果你想知道为什么 Rust 选择让你重复 P
和 D
的界限,而它可以完美地推断出它们,那是因为它关心你。更具体地说,它关心 6 个月后的你,以及下一个维护者。因此,采取一次编写并多次阅读的立场,它迫使您复制边界,以便以后您不必想知道它们是什么,并递归地向下钻取每个 type/function 用于痛苦地聚合所有碎片。在 Rust 中,下次您阅读该函数时,您将获得所有信息。
如何将带有签名 impl<P, D> EcsClient<P, D> where P: ProvideAwsCredentials, D: DispatchSignedRequest
的 EcsClient
的实例作为 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
是结构而不是特征。谷歌搜索没有提供太多帮助,因为我不知道要搜索的正确术语。
This question 似乎暗示我应该能够声明像 fn my_func(client: &EcsClient) { ... }
这样的函数并且它会起作用,那么为什么上面的例子不起作用?
我对语法的理解有误。 P
和 D
似乎是占位符,就像 T
一样。我需要指定 这些类型是什么 ,所以签名现在看起来像这样:
fn get_task_definition_revisions<P: ProvideAwsCredentials, D: DispatchSignedRequest>(client: &EcsClient<P, D>) {
...
}
我没有在函数体中使用P
或D
,但必须声明它们。
完整示例现在如下所示:
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);
}
我仍然不完全确定为什么这样做或需要这样做,但我希望这个答案对其他人有所帮助。
问题是 EcsClient
不是类型,它是构建类型的蓝图(也称为 "type constructor")。
因此,当需要类型时,您不能使用 just EcsClient
,无论是在函数中还是对于结构成员;相反,每次都必须通过指定其通用参数来使用它来构建类型。
因此,第一步是引入类型参数:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>) {}
然而,现在编译器会抱怨 P
和 D
没有足够的约束:EcsClient
只接受一种非常特殊的 P
和 D
!
因此,下一步是 look-up 在 EcsClient
的定义中为 P
和 D
指定的边界并应用它们。此时只有 copy/paste:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
where P: ProvideAwsCredentials,
D: DispatchSignedRequest
{
}
然后你就是金色的。
如果您需要 更多 P
或 D
的功能来实现此特定功能,请随时通过使用 [= 添加更多边界来充分限制它们25=]:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
where P: ProvideAwsCredentials + 'static,
D: DispatchSignedRequest
{
}
如果你想知道为什么 Rust 选择让你重复 P
和 D
的界限,而它可以完美地推断出它们,那是因为它关心你。更具体地说,它关心 6 个月后的你,以及下一个维护者。因此,采取一次编写并多次阅读的立场,它迫使您复制边界,以便以后您不必想知道它们是什么,并递归地向下钻取每个 type/function 用于痛苦地聚合所有碎片。在 Rust 中,下次您阅读该函数时,您将获得所有信息。