首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >处理“预期fn指针,找到fn项”

处理“预期fn指针,找到fn项”
EN

Stack Overflow用户
提问于 2022-04-22 20:43:21
回答 2查看 477关注 0票数 0

我已经做了很多谷歌搜索,试图找出这一个。我有一个库,我希望人们能够传递对自定义“签名者”函数的引用(作为直接提供秘密密钥的替代方法)。这是我最近面临的问题:

代码语言:javascript
运行
复制
mismatched types

expected fn pointer, found fn item

note: expected enum `std::option::Option<&for<'r, 's> fn(&'r [u8; 20], &'s [u8; 32]) -> &[u8; 32]>`
         found enum `std::option::Option<&for<'r, 's> fn(&'r [u8; 20], &'s [u8; 32]) -> &[u8; 32] {signer_func::<'_>}>`rustc(E0308)
check_handle.rs(28, 17): expected fn pointer, found fn item

我试图将该函数传递给一个通过系统传递的struct,如:

代码语言:javascript
运行
复制
pub struct Params<'a> {
    pub signer: Option<&'a fn(address: &[u8; 20], data: &[u8; 32]) -> &'a[u8; 32]>,
}

我尝试过按我在大多数地方看到的那样定义函数,但是编译器抱怨我不能转换非原始类型:

代码语言:javascript
运行
复制
pub fn signer_func<'a>(address: &[u8; 20], data: &[u8; 32]) -> &'a[u8; 32] {
    . . .
}

. . .

let params = Params {
    signer: Option::from(&signer_func as &fn(&[u8; 20], &[u8; 32]) -> &[u8; 32])
};

我试着使用Fn特性并围绕它重新设计我的结构和函数,但是我仍然停留在我需要将该特性包括在结束函数中的地方(我会得到错误,认为该特性是未定义的)。

但是,这就是我需要去研究的方向吗?我需要把重点放在弄清楚为什么目标函数不能识别特征名称吗?感觉就像以我现在的方式使用fn是最简单的,“指针对项”似乎是一些琐碎的东西,但我只是找不到它。

编辑

好吧,我又开始使用Fn特征了,我有这样的想法:

代码语言:javascript
运行
复制
pub struct SignRequest {
    pub address: [u8; 20],
    pub data: [u8; 32]
}

pub struct Signer<CustomSigner>
where 
    CustomSigner: Fn(&SignRequest) -> [u8; 32],
{
    pub address: [u8; 20],
    pub data: [u8; 32],
    pub sign: CustomSigner
}

impl<CustomSigner> Signer<CustomSigner>
where
    CustomSigner: Fn(&SignRequest) -> [u8; 32],
{
    pub fn new(address: [u8; 20], data: [u8; 32], sign: CustomSigner) -> Signer<CustomSigner> {
        Signer { address, data, sign }
    }
}

pub struct SignaturesParams<CustomSigner: for<'r> std::ops::Fn(&'r SignRequest) -> [u8; 32]> {
    pub address: H160,
    pub private_key: Option<H256>,
    pub signer: Option<Signer<CustomSigner>>,
    pub data: [u8; 32],
}

pub async fn signatures<CustomSigner: for<'r> std::ops::Fn(&'r SignRequest) -> [u8; 32]>(params: &SignaturesParams<CustomSigner>) -> Result<Signatures, Box<dyn std::error::Error + Sync + Send>> {
 
. . . 
}

这可以很好地编译(我的IDE建议并添加了疯狂的“查找”内容),但是当我试图在另一个模块中使用SignaturesParams时,我遇到了一些问题:

代码语言:javascript
运行
复制
let signatures_params = SignaturesParams {
    address: params.eth_address.clone(),
    private_key: params.private_key.clone(),
    data: hash_message(serde_json::to_string(&message)?),
    signer: Option::None
};
代码语言:javascript
运行
复制
type inside `async fn` body must be known in this context

cannot infer type for type parameter `CustomSigner` declared on the struct `SignaturesParams`rustc(E0698)
request.rs(34, 19): cannot infer type for type parameter `CustomSigner` declared on the struct `SignaturesParams`

我尝试过将该类型引入范围的各种排列(例如,在signatures_params块上容器函数的定义中包括了长"for“行),但还没有找到正确的方法来识别它。

我显然有点摸索,我现在的结构不是最优的--我只是想弄清楚它是如何连接在一起的。谢谢你的建议!

最终更新

最后,我放弃了我试图使之工作的流(即,在前面定义一个闭包,并通过几个结构传递它,最终由一个终止函数执行)。相反,我将这些步骤分解为更小的部分,使我能够独立地构建消息,然后将这些消息和自定义闭包直接传递给签名者结构。

代码语言:javascript
运行
复制
#[derive(Copy, Clone)]
pub struct SignData {
    pub address: [u8; 20],
    pub data: [u8; 32],
    pub private_key: Option<[u8; 32]>,
}

#[derive(Clone)]
pub struct Signature {
    pub data: String,
}

#[derive(Clone)]
pub struct Signer<F, Fut>
where
    F: Fn(SignData) -> Fut,
    Fut: Future<Output = Signature>,
{
    pub sign_func: F,
}

impl<F, Fut> Signer<F, Fut>
where
    F: Fn(SignData) -> Fut,
    Fut: Future<Output = Signature>,
{
    pub fn new(signer: F) -> Signer<F, Fut> {
        Signer { sign_func: signer }
    }

    pub fn sign(self, sign_data: SignData) -> Fut {
        (self.sign_func)(sign_data)
    }
}

然后,可以以这种方式定义和使用要与它一起使用的闭包。

代码语言:javascript
运行
复制
let closure = async move |x: SignData| { 
. . .
    Signature { data: some_String } 
};

let signature = Signer::new(closure).sign(some_SignData).await.data

我认为这对我现在会很有帮助。谢谢你的帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-04-25 08:21:10

初始代码的问题是,虽然可以将fn项(编译器称为fn ... {name})强制转换为fn指针(fn ...),但该属性不是递归的:不能将对fn项的引用转换为对fn指针的引用。也就是说,signer_func as fn(&[u8; 20], &[u8; 32]) -> &'a [u8; 32]工作,但&signer_func as &fn(&[u8; 20], &[u8; 32]) -> &'a [u8; 32]不工作。修复很简单:强制转换,然后接受引用。就是,&(signer_func as fn(&[u8; 20], &[u8; 32]) -> &'a [u8; 32])

不过,&fn()看上去一点也不对:fn()已经是一个指针,因此&fn()是冗余的双重定向。你可能想改变这一点。

第二段代码的问题是编译器无法推断出CustomSigner的类型,因为您提供了None。您需要显式地指定此类型参数。如果不查看代码,我就无法知道它需要什么,但是假设您在本例中并不真正需要它,您可以指定一个虚拟类型,例如fn(&SignRequest) -> [u8; 32]

票数 1
EN

Stack Overflow用户

发布于 2022-04-22 20:46:59

问题是你们把太多的生命捆绑在一起。

代码语言:javascript
运行
复制
pub signer: Option<&'a fn(address: &[u8; 20], data: &[u8; 32]) -> &'a[u8; 32]>

这需要对返回一个片段(也是生存期'a)的函数的引用(存在于生存期'a)。如果那些生命是不相容的,那么它就不会打字。考虑创建两个独立的生命周期。

代码语言:javascript
运行
复制
pub struct Params<'a, 'b> {
  pub signer: Option<&'a fn(address: &[u8; 20], data: &[u8; 32]) -> &'b[u8; 32]>,
}

不过,正如您已经注意到的,Fn特性是更好的选择。您很少想借用Fn,所以我建议您使用signer的类型

代码语言:javascript
运行
复制
pub signer: Option<Box<dyn Fn(address: &[u8; 20], data: &[u8; 32]) -> &'a [u8; 32]>>

注意Box而不是&,以及关键字dyn,这是Rust更新版本中推荐的特征对象,总有一天会被要求的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71974428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档