无法满足 Into<i64> 特征界限

Unable to satisfy Into<i64> trait bound

出于某种原因,我无法通过网络搜索找到任何答案。

所以我有一个使用 libc 板条箱(一个简单的包装器)的类型同义词:

pub type SyscallResult<R: Into<i64>> = Result<R, c_int>;

Into<i64> 的意义在于一些系统调用有 i32i64 结果,但 errno 始终是 i32。 (c_int -> i32)

在函数签名中使用 std 提供的具体类型没有问题。

pub fn handle_syscall_result(result: SyscallResult<i64>) -> i64
{
    match result {
        Ok(status: i64) => status,
        Err(errno: c_int) => {
            let err = unsafe { CStr::from_ptr(libc::strerror(errno)) };
            println!("{:?}", err);
            errno as i64
        }
    }
}

但是当我尝试将特征绑定传播到函数的签名中时,事情开始变得混乱:

fn new_syscall_result<T>(status: Option<T>) -> SyscallResult<i64>
where
    T: Into::<i64>,
{
    let errno: c_int = errno();

    match errno {
        -1 => Err(errno),
        _ => Ok(status.unwrap_or(errno)),
    }
}

给予

error[E0308]: mismatched types
  --> 
   |
35 | fn new_syscall_result<T>(status: Option<T>) -> SyscallResult<i64>
   |                       - this type parameter
...
43 |         _ => Ok(status.unwrap_or(errno)),
   |                 ^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found type parameter `T`
   |
   = note:        expected type `i64`
           found type parameter `T`

这让它看起来像是在做正确的事情,因为 i32 被转换为 i64,但由于某种原因它不满足特征界限 T?

展开 Option<T> 应该自然地给出 T 并且从我从 std::convert::From 文档中读到的内容来看,Into<i64> 应该为 i64 实现为很好(反身性),尽管即使它没有被强制转换 From<i32> for i64 也是一个有效的实现,这意味着 Into<i64> for i32 应该存在。

将 return 类型切换为 SyscallResult<T> 也没有任何区别

error[E0308]: mismatched types
  --> 
   |
35 | fn new_syscall_result<T>(status: Option<T>) -> SyscallResult<T>
   |                       - this type parameter
...
43 |         _ => Ok(status.unwrap_or(errno)),
   |                                  ^^^^^ expected type parameter `T`, found `i32`
   |
   = note: expected type parameter `T`
                        found type `i32`

您需要显式调用 into():

        _ => Ok(status.map(Into::<i64>::into).unwrap_or(errno.into())),
//                     ^^^^^^^^^^^^^^^^^^^^^^

status 是一个 Option<T>,你想要一个 Option<i64> 的机器人。为此,我们使用 Option::map.

转换 Option 中包含的类型

你的代码还有一个问题:

        _ => Ok(status.map(Into::<i64>::into).unwrap_or(errno.into())),
//                                                      ^^^^^^^^^^^^

errno 是一个 c_int,所以在大多数平台上是一个 i32,但我们需要一个 i64。同样,必须使用 into() 来转换类型。这里不需要显式类型注释,编译器可以从上下文中推断出正确的类型。或者,您也可以在此处使用强制转换:

        _ => Ok(status.map(Into::<i64>::into).unwrap_or(errno as i64)),