My function name is a string. If I want to implement such a call method, how can I implement it?

fn add(a:i32, b:i32) -> i32{
    a+b
}

fn main(){
	let fname = "add"; 
	let c = fname(5, 6);
	println!("add :{}", c);

}

My function name is a string. If I want to implement such a call method, how can I implement it?

The short answer is that you can't, because the function's name doesn't exist at runtime. It may exist as a symbol in the executable, but that would require finding and parsing the executable (which would depend on the executable format), and figuring out where the function code was mapped in memory (which may be impossible in general, and would require knowledge of how the operating system loads executables). Jumping to code like that would also require a fair bit of unsafe Rust.

A better question to ask is: why do you want to do this? You may be trying to solve a different problem with the wrong tool here.

1 Like

Rust is not a dynamic language, so there is no good way to do this. You should rethink your problem and redesign your program to avoid needing to call functions by name. What else to do depends on what you need to achieve — you may need enums, traits, closures, or a maybe a parser/serializer. There is no direct equivalent.

But if you have to, there are multiple poor ways to do it:

let c = match fname {
   "add" => add(5, 6),
   _ => panic!("bad name");
};

If all functions you want to call take and return same types of arguments, then you can use a HashMap<String, fn(i32, i32) -> i32> or similar.

4 Likes

Another alternative to the HashMap approach if your functions all have the same type would be to map from strings to functions within a match (playground example):

    let func : fn (i32, i32) -> i32 = match fname {
	    "add" => add,
	    "sub" => sub,
	    _     => unimplemented!(), // Handle a failed match here
    };

If you're coming from a javascript background and using something like json to take in method calls from somewhere else, you can do something like this for a fixed number of functions that you would define in the enum. This way though, you would have to predefine the functions that you allow to be called.

use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(tag = "fname", rename_all = "lowercase")]
enum Method {
    Add { a: u64, b: u64 },
}

impl Method {
    fn call(&self) -> serde_json::Value {
        match self {
            Method::Add { a, b } => serde_json::json!(a + b),
        }
    }
}

fn main() {
    let method_str = r#"{"fname":"add","a":1,"b":2}"#;
    let method: Method = serde_json::from_str(method_str).unwrap();
    let result = method.call();
    println!("{:?}", result);
}

The serde_json::Value type is the trick needed to be able to take a variety of value types as a return since it can encapsulate numbers, strings, arrays, maps, etc.

1 Like

Thank you very much for your discussion. Maybe rust can add such a method and ability to deal with similar problems while considering its own security, efficiency and ease of use in the future. I write it directly as characters, but in fact, it can define a hook function to call other functions.

For example:

fn add(a:i32, b:i32) -> i32{

a+b

}

fn main(){

let fname = "add";

let fname = hook(fname);

let c = fname(5, 6);

println!("add :{}", c);

}

You may say why there is such a requirement to add such a function to the compiler. I recently developed a project for using trust. Because it does not support such calls, I have to write about 120000 lines of code, but many things are repeated. For example, I have an entry to call different mods according to the situation, At this time, my project had 65 mod + 18000 FN, which made me feel that I had done a lot of unnecessary work when writing programs.

Today, every language has vitality. We should look at this issue from the perspective of development.

There is vanishingly little chance that Rust ever becomes a dynamic language. It would be just too much of a change.


Anyway, with callback/hook systems, it is usually the case that when you add a hook, you have a function pointer to it. You probably don't need to call it by its name. You could just store function pointers instead. However, it is still not clear from your example what it is that makes you think it is not doable. Your example is overly simplified to the point where it does not represent your actual problem.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.