< 返回版块

viruscamp 发表于 2023-04-12 22:05

use std::io::{ Result, Error, ErrorKind, Write };

pub fn should_not_call<A, B, R>(_a: A, _b: B) -> Result<R> {
    Err(Error::new(ErrorKind::Unsupported,  "should not be called"))?
}

pub struct Dump<W: Write> {
    pub w: W,
    pub write_u64: fn(&mut Dump<W>, u64) -> Result<usize>,
}

pub fn write_le<W: Write>(d: &mut Dump<W>, v: u64) -> Result<usize> {
    d.w.write(u64::to_le_bytes(v).as_slice())
}

fn ok<W: Write>(w: W) {
    let mut write_u64: fn(_,_) -> _ = write_le::<W>;
    write_u64 = should_not_call;
}

fn failed<W: Write>(w: W) {
    let mut d = Dump {
        w,
        write_u64: write_le::<W>,
    };
    //d.write_u64 = should_not_call;
    //d.write_u64 = should_not_call as fn(_,_) -> _;
    //d.write_u64 = should_not_call as for<'a> fn(&'a mut Dump<W>, u64) -> Result<usize>;
}

如上,should_not_call 这个通用泛型函数,可以赋值给 ok 的变量 write_u64,但没法赋值给 failed 的 d.write_u64

注释掉的第一种写法,报错 expected fn pointer found fn item
注释掉的第二种写法,报错 mismatched types: one type is more general than the other
注释掉的第三种写法,报错 non-primitive cast: invalid cast

评论区

写评论
Bai-Jinlin 2023-04-13 10:21

unsafe倒是能解决,但是我总感觉有更聪明的方法

Grobycn 2023-04-12 23:00

看起来又是HRTB的关系

d.write_u64 的类型是 for<'a> fn(&'a mut Dump<W>, u64) -> Result<usize>

should_not_call 的类型只能得到 fn(&'a mut Dump<W>, u64) -> Result<usize>

作者 viruscamp 2023-04-12 22:11

这样写能过

pub fn should_not_call_ref<A, B, R>(_a: &mut A, _b: B) -> Result<R> {
    Err(Error::new(ErrorKind::Unsupported,  "should not be called"))?
}

fn passed<W: Write>(w: W) {
    let mut d = Dump {
        w,
        write_u64: write_le::<W>,
    };
    d.write_u64 = should_not_call_ref;
}
作者 viruscamp 2023-04-12 22:09

这样的错误是不是更接近根源?

fn failed2<W: Write>(w: W) {
    let mut fn1: fn(&mut Dump<W>, u64) -> Result<usize> = write_le::<W>;
    let mut fn2: fn(_,_) -> _ = write_le::<W>;
    fn2 = fn1;
    fn1 = fn2; // 错误: mismatched types: one type is more general than the other
}
1 共 4 条评论, 1 页