如何解决为什么比赛认为这些手臂不一样?
(PDP仿真器中的指令解码)
我有一个巨大的匹配集,其中每个手臂都返回一个函数指针和一个名称。这是摘录
match (inst & 0o170000) >> 12 {
0o00 => match (inst & 0o007700) >> 6 {
0o00 => match inst & 0o77 {
00 => (Cpu::halt,"halt"),01 => (Cpu::halt,"wait"),02 => (Cpu::halt,"rti"),03 => (Cpu::halt,"bpt"),04 => (Cpu::halt,"iot"),
这些比赛的每一行都说(Cpu :: halt,“ xxx”)。编译愉快。但是,当然,我想要真正的功能,所以我更改了第一个。
match (inst & 0o170000) >> 12 {
0o00 => match (inst & 0o007700) >> 6 {
0o00 => match inst & 0o77 {
00 => (Cpu::mov,
停止和移动都具有相同的签名
impl Cpu{
pub fn halt(&mut self,z:Word)->Result<(),Exception>{Ok(())}
pub fn mov(&mut self,z:Word) ->Result<(),Exception>{
let (mut ss,mut dd) = self.decode_ssdd(z,false)?;
let t = self.fetch_word(&mut ss)?;
self.psw &= !statusflags::PS_V;
self.set_status(t);
self.store_word(&mut dd,t)?;
Ok(())
}
}
但是rustc然后抱怨
error[E0308]: `match` arms have incompatible types
--> src\cpu.rs:83:31
|
81 | 0o00 => match inst & 0o77 {
| _____________________________-
82 | | 00 => (Cpu::mov,| | ------------------ this is found to be of type `(for<'r> fn(&'r mut cpu::Cpu,u16) -> std::result::Result<(),common::Exception> {instructions::<impl cpu::Cpu>::mov},&str)`
83 | | 01 => (Cpu::halt,| | ^^^^^^^^^^^^^^^^^^^ expected fn item,found a different fn item
84 | | 02 => (Cpu::halt,... |
90 | | _ => unreachable!(),91 | | },| |_____________________- `match` arms have incompatible types
|
= note: expected type `(for<'r> fn(&'r mut cpu::Cpu,_) -> std::result::Result<_,_> {instructions::<impl cpu::Cpu>::mov},&str)`
found tuple `(for<'r> fn(&'r mut cpu::Cpu,_> {instructions::<impl cpu::Cpu>::halt},&'static str)`
错误的必要部分似乎是最后两行,该行表明发现的元组之间的区别是一个是(fn,&str),另一个是(fn,&'static str)。但是除了函数名称外,它们是相同的。
我还注意到,前面的错误显示“期望的fn项,找到了另一个fn项”,但这不是最后两行所说的。
解决方法
考虑这种简化的情况:
pub struct Exception{}
pub struct Cpu {}
impl Cpu{
pub fn halt(&mut self)->Result<(),Exception>{Ok(())}
pub fn mov(&mut self) ->Result<(),Exception>{Ok(())}
}
然后编译成功:
pub fn foo(cpu:&mut Cpu,i:i32) -> Result<(),Exception> {
let f = match i {
0 => Cpu::halt,_ => Cpu::mov,};
f(cpu)
}
但这会产生与您看到的相同的错误
pub fn bar(cpu:&mut Cpu,Exception> {
let f = match i {
0 => (Cpu::halt,"halt"),_ => (Cpu::mov,"mov"),};
f.0(cpu)
}
在bar
情况下,编译器似乎无法推断出从匹配项返回的元组的类型。通过添加foo
并查看错误消息,我们可以找出在q:() = f;
情况下编译器为f推导的类型。是
17 | let q:() = f;
| -- ^ expected `()`,found fn pointer
| |
| expected due to this
|
= note: expected unit type `()`
found fn pointer `for<'r> fn(&'r mut Cpu) -> std::result::Result<(),Exception>`
然后我们可以明确声明该类型,以供元组获取bar
进行编译(但我们可以删除for<'r> ... 'r
位)
pub fn bar(cpu:&mut Cpu,Exception> {
let f: (fn(&mut Cpu) -> Result<(),Exception>,&str) = match i {
0 => (Cpu::halt,};
f.0(cpu)
}
我个人会使用type
语句来消除噪音
type CpuFn = fn(&mut Cpu) -> Result<(),Exception>;
pub fn bar(cpu:&mut Cpu,Exception> {
let f: (CpuFn,};
f.0(cpu)
}
您可以看到完整的有效版本here
ASIDE:
值得注意的是,使用q:() = Cpu::halt
技巧,我们发现Cpu::halt
的类型为fn item for<'r> fn(&'r mut Cpu) -> Result<(),Exception> {Cpu::halt}
,与foo
中的匹配返回的类型不同。编译器将两个分支与类型组合在一起
fn(&mut Cpu) -> Result<(),Exception> {Cpu::halt}
和
fn(&mut Cpu) -> Result<(),Exception> {Cpu::mov}
转换为普通类型。
fn(&mut Cpu) -> Result<(),Exception>
但不愿意组合类型
(fn(&mut Cpu) -> Result<(),Exception> {Cpu::halt},&str)
(fn(&mut Cpu) -> Result<(),Exception> {Cpu::mov},&str)
进入
(fn(&mut Cpu) -> Result<(),&str)
我通常找不到有关对匹配分支的返回值执行哪些转换的任何信息,也找不到有关锈中fn item
和fn pointer
类型之间的差异的任何信息
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。