简体   繁体   English

如果Rust中的语句类型不匹配,则使用递归函数

[英]Recursive function if statement mismatched types in Rust

fn recursive_binary_search<T: Ord>(list: &mut [T], target: T) -> bool {
    if list.len() < 1 {
        return false;
    }
    let guess = list.len() / 2;
    if target == list[guess] {
        return true;
    } else if list[guess] > target {
        return recursive_binary_search(&mut list[0..guess], target);
    } else if list[guess] < target {
        return recursive_binary_search(&mut list[guess..list.len()], target);
    }
}

the compiler throws an error on if target == list[guess] saying if target == list[guess]说,编译器将引发错误

src/main.rs:33:5: 39:6 error: mismatched types [E0308]
src/main.rs:33     if target == list[guess] {
                   ^
src/main.rs:33:5: 39:6 help: run `rustc --explain E0308` to see a detailed explanation
src/main.rs:33:5: 39:6 note: expected type `bool`
src/main.rs:33:5: 39:6 note:    found type `()`
error: aborting due to previous error

I can't figure out how to rewrite this function to satisfy the type checker. 我不知道如何重写此函数以满足类型检查器。 I assume it is because I have the return type set to bool and there is a return function call? 我以为是因为我将返回类型设置为bool,并且有返回函数调用?

The issue here is that Rust evaluates the if/else if/else if block as the return value because it lacks an else clause, and statements which don't evaluate to any value have the type () . 这里的问题是Rust由于缺少else子句而将if/else if/else if作为返回值进行评估,而没有评估为任何值的语句的类型为() Incidentally, the code you've presented does exhaustively cover all possibilities (the item at the current index of the slice is either equal to, less than, or greater than the target), but the compiler doesn't know that unless you give it an else clause at the end: 顺便说一句,您提供的代码确实涵盖了所有可能性(切片的当前索引处的项目等于,小于或大于目标),但是除非您给出它,否则编译器不知道最后的else子句:

fn recursive_binary_search<T: Ord + Eq>(list: &[T], target: T) -> bool {
    if list.len() < 1 {
        return false;
    }
    let guess = list.len() / 2;
    if target == list[guess] {
        return true;
    } else if list[guess] > target {
        return recursive_binary_search(&list[0..guess], target);
    } else {
        return recursive_binary_search(&list[guess..list.len()], target);
    }
}

PS: This function doesn't require mutable references, so I'd recommend using regular references as in my code above. PS:此函数不需要可变的引用,因此我建议像上面的代码中那样使用常规引用。

EDIT: For posterity, here's the same code w/o explicit returns: 编辑:对于后代,这是不带显式返回的相同代码:

fn recursive_binary_search<T: Ord>(list: &[T], target: T) -> bool {
    if list.len() < 1 {
        return false;
    }
    let guess = list.len() / 2;
    if target == list[guess] {
        true
    } else if list[guess] > target {
        recursive_binary_search(&list[0..guess], target)
    } else {
        recursive_binary_search(&list[guess..list.len()], target)
    }
}

dikaiosune's answer explains the problem: the resulting type of your if is () , which is being returned instead of a bool . dikaiosune的答案解释了这个问题: if的结果类型是() ,而不是bool返回。

Here's a few ways of writing the code a bit more idiomatically: 这是一些习惯用法编写代码的几种方法:

I'd start by writing it with implicit returns: 我先用隐式返回值编写它:

fn recursive_binary_search<T: Ord + Eq>(list: &[T], target: T) -> bool {
    if list.len() < 1 {
        return false;
    }

    let guess = list.len() / 2;

    if target == list[guess] {
        true
    } else if list[guess] > target {
        recursive_binary_search(&list[0..guess], target)
    } else {
        recursive_binary_search(&list[guess..list.len()], target)
    }
}

Then I'd perform the compare just once, instead of potentially twice. 然后,我将只执行一次比较,而不是可能执行两次。 Could save a bit of time if comparisons are expensive, but it also looks nice with the match : 如果比较昂贵,可以节省一些时间,但是与match看起来也不错:

use std::cmp::Ordering;

fn recursive_binary_search<T: Ord + Eq>(list: &[T], target: T) -> bool {
    if list.is_empty() {
        return false;
    }

    let guess = list.len() / 2;

    match target.cmp(&list[guess]) {
        Ordering::Less    => recursive_binary_search(&list[..guess], target),
        Ordering::Greater => recursive_binary_search(&list[guess..], target),
        Ordering::Equal   => true,
    }
}

You can also drop the beginning and end parts of the ranges, and use is_empty for the guard clause. 您还可以删除范围的开头和结尾部分,并将is_empty用作guard子句。

Then there's the problem of the stack overflow if you search for a value larger than the biggest value... you need to ignore the pivot when recurring: 然后,如果您搜索的值大于最大值,则会出现堆栈溢出的问题……在重复执行时,您需要忽略数据透视表:

use std::cmp::Ordering;

fn recursive_binary_search<T: Ord>(list: &[T], target: T) -> bool {
    if list.is_empty() {
        return false;
    }

    let guess = list.len() / 2;

    match target.cmp(&list[guess]) {
        Ordering::Less    => recursive_binary_search(&list[..guess], target),
        Ordering::Greater => recursive_binary_search(&list[guess+1..], target),
        Ordering::Equal   => true,
    }
}

fn main() {
    assert!(!recursive_binary_search(&[1,2,3,4,5], 0));
    assert!(recursive_binary_search(&[1,2,3,4,5], 1));
    assert!(recursive_binary_search(&[1,2,3,4,5], 2));
    assert!(recursive_binary_search(&[1,2,3,4,5], 3));
    assert!(recursive_binary_search(&[1,2,3,4,5], 4));
    assert!(recursive_binary_search(&[1,2,3,4,5], 5));
    assert!(!recursive_binary_search(&[1,2,3,4,5], 6));
}

If you aren't implementing this for learning purposes, use the built-in binary_search . 如果您不是出于学习目的实现此功能,请使用内置的binary_search

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM