简体   繁体   中英

How to construct a concrete type in a generic function?

With what would I need to replace /* type */ so that o_f could equal None , Some(a) , Some(b) , or Some(/* a different function with the same signature */) ?

fn func<T: Copy + Ord>(x: &mut Option<Box<Node<T>>>)
{
    let mut o_f: /* type */ = None;
    let mut result_of_f: Option<bool> = None;
    let mut o_b_n_num = Some(Box::new(Node::new(1)));

    // ...

    if let Some(f) = o_f
    {
        result_of_f = Some(f(x) && f(&mut o_b_n_num));
    }

    // ...
}

What you're trying to do is not possible. You have a function generic over T but internally you're trying to use concrete type i32 . Rust monomorphizes generic functions based on what types they get called with. Take this program for example:

fn func<F, T>(f: F, t: T)
    where F: Fn(T)
{
    f(t);
}

struct S;
struct R;

fn main() {
    func(|x| {}, S);
    func(|x| {}, R);
}

Will get compiled to something like:

fn func_S(f: impl Fn(S), s: S)
{
    f(s);
}

fn func_R(f: impl Fn(R), r: R)
{
    f(r);
}

struct S;
struct R;

fn main() {
    func_S(|s| {}, S);
    func_R(|r| {}, R);
}

Which is all well and good, but what if we go back and change the first function to this (which is essentially what you're trying to do):

fn func<F, T>(f: F, t: T)
    where F: Fn(T)
{
    f(t);
    f(1); // concrete type i32, not type T
}

struct S;
struct R;

fn main() {
    func(|x| {}, S);
    func(|x| {}, R);
}

Now it wouldn't compile, but if we imagined it did then it'd like something like this:

fn func_S(f: impl Fn(S), s: S)
{
    f(s);
    f(1); // error! f expects S not i32
}

fn func_R(f: impl Fn(R), r: R)
{
    f(r);
    f(1); // error! f expects R not i32
}

struct S;
struct R;

fn main() {
    func_S(|s| {}, S);
    func_R(|r| {}, R);
}

You see how that makes no sense at all? You're trying to pass a i32 to functions that expect S and R .

Now, you have a couple options. If you want some data structure of just i32 s then you don't need to make it generic and can define it just for i32 s. If you want a generic structure where, if some node is missing, and you want populate it with a "default" node (perhaps in the case of Node<i32> that default node is Node::new(1) ) then you can bind T on Default and write something like this:

#[derive(Default)]
struct Node<T: Default>(T);

#[derive(Default)]
struct S;
#[derive(Default)]
struct R;

fn func<F, T>(f: F, t: Option<Node<T>>)
    where T: Default, F: Fn(Node<T>)
{
    f(t.unwrap_or_default());
}

fn main() {
    func(|x| {}, Some(Node(S)));
    func(|x| {}, Some(Node(R)));
    func(|x: Node<i32>| {}, None);
}

Now your function is truly generic over T and handles the case of all Node<T> including Node<i32> .

See also

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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