iTranslated by AI
Binding Variables with Trait Bounds in Rust Using dyn
Naturally, Rust generally requires the type of a value bound to a variable to be determined at compile time. However, in some cases, you may want to decide the type at runtime.
Example code
For example, let's say you have a program like this where you select and use various LLMs.
trait Responder {
fn respond(&self) -> Result<String, std::io::Error>;
}
struct OpenAI {
model: String,
}
impl OpenAI {
fn new(model: &str) -> Self {
Self {
model: model.to_string(),
}
}
}
impl Responder for OpenAI {
fn respond(&self) -> Result<String, std::io::Error> {
Ok(String::from("I'm a chatGPT."))
}
}
struct Google {
model: String,
}
impl Google {
fn new(model: &str) -> Self {
Self {
model: model.to_string(),
}
}
}
impl Responder for Google {
fn respond(&self) -> Result<String, std::io::Error> {
Ok(String::from("I'm a gemini."))
}
}
fn main() {
let selected_model = "openai";
let model = if selected_model == "openai" {
OpenAI::new("chatgpt")
} else {
Google::new("gemini")
};
}
However, this code will result in an error. A compilation error occurs because the if and else branches return different types (OpenAI and Google).
cargo check
Checking dyn_trait v0.1.0 (~/Develop/for_zenn/dyn_trait)
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:46:9
|
43 | let model = if selected_model == "openai" {
| _________________-
44 | | OpenAI::new("chatgpt")
| | ---------------------- expected because of this
45 | | } else {
46 | | Google::new("gemini")
| | ^^^^^^^^^^^^^^^^^^^^^ expected `OpenAI`, found `Google`
47 | | };
| |_____- `if` and `else` have incompatible types
For more information about this error, try `rustc --explain E0308`.
error: could not compile `dyn_trait` (bin "dyn_trait") due to 1 previous error
Here, you can determine the type at runtime by defining the variable with a constraint as a type that implements the Responder trait using dyn. Also, because the size of the value is unknown at compile time, we wrap it in a Box. In terms of usage, I think it's similar to a generic type T in a function.
fn main() {
let selected_model = "openai";
let model: Box<dyn Responder> = if selected_model == "openai" {
Box::new(OpenAI::new("chatgpt"))
} else {
Box::new(Google::new("gemini"))
};
}
By the way, you can even display the output like this. Since it's fixed to "openai" in the if statement, it will simply output I'm a chatGPT. and finish.
fn main() {
let selected_model = "openai";
let model: Box<dyn Responder> = if selected_model == "openai" {
Box::new(OpenAI::new("chatgpt"))
} else {
Box::new(Google::new("gemini"))
};
println!("{}", model.respond().unwrap());
}
References
Discussion