Return Generic Type in Rust

Background: I have a large serde_json value that I want to be read-only (the authoritative source is an encrypted SQLite DB and should only be updated when that gets updated)

The issue, I would like a single get function that returns a generic type


<span style="font-weight:bold;color:#a71d5d;">use</span><span style="color:#323232;"> serde_json;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">pub struct </span><span style="color:#323232;">Configuration {
</span><span style="color:#323232;">    config: serde_json::Value,
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">impl </span><span style="color:#323232;">Configuration {
</span><span style="color:#323232;">    async </span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">get</span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">amp;self, key: </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">amp;</span><span style="font-weight:bold;color:#a71d5d;">str</span><span style="color:#323232;">) -> Result {
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> tmp_value: </span><span style="font-weight:bold;color:#a71d5d;">= &</span><span style="color:#323232;">amp;self.config[</span><span style="color:#183691;">"test"</span><span style="color:#323232;">];
</span><span style="color:#323232;">
</span><span style="color:#323232;">        </span><span style="font-style:italic;color:#969896;">// This would be repeated for String, bool, etc
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> tmp_value.</span><span style="color:#62a35c;">is_i64</span><span style="color:#323232;">() {
</span><span style="color:#323232;">            </span><span style="font-weight:bold;color:#a71d5d;">match</span><span style="color:#323232;"> tmp_value.as_i64 {
</span><span style="color:#323232;">                </span><span style="color:#0086b3;">Some</span><span style="color:#323232;">(x) </span><span style="font-weight:bold;color:#a71d5d;">=> </span><span style="color:#0086b3;">Ok</span><span style="color:#323232;">(x),
</span><span style="color:#323232;">                </span><span style="color:#0086b3;">Err</span><span style="color:#323232;">(e) </span><span style="font-weight:bold;color:#a71d5d;">=> </span><span style="color:#0086b3;">Err</span><span style="color:#323232;">(()),
</span><span style="color:#323232;">            }
</span><span style="color:#323232;">        } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;">            </span><span style="color:#0086b3;">Err</span><span style="color:#323232;">(())
</span><span style="color:#323232;">        }
</span><span style="color:#323232;">    }
</span><span style="color:#323232;">}
</span>

However I get: “mismatched types expected type parameter T found type i64”

Is it even possible to return multiple types from a single function?

EDIT: SOLUTION

Here is the solution I came up with:


<span style="font-weight:bold;color:#a71d5d;">pub struct </span><span style="color:#323232;">Configuration {}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">impl </span><span style="color:#323232;">Configuration {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">get </span><span style="color:#323232;">std::str::FromStr</span><span style="font-weight:bold;color:#a71d5d;">></span><span style="color:#323232;">() -> Result {
</span><span style="color:#323232;">        </span><span style="color:#0086b3;">Ok</span><span style="color:#323232;">(T::from_str(</span><span style="color:#183691;">"1234"</span><span style="color:#323232;">);
</span><span style="color:#323232;">    }
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> my_conf_val </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Configuration::get();
</span><span style="color:#323232;">}
</span>
wulf,

SOLUTION:

Here is the solution I came up with:


<span style="font-weight:bold;color:#a71d5d;">pub struct </span><span style="color:#323232;">Configuration {}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">impl </span><span style="color:#323232;">Configuration {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">get </span><span style="color:#323232;">std::str::FromStr</span><span style="font-weight:bold;color:#a71d5d;">></span><span style="color:#323232;">() -> Result {
</span><span style="color:#323232;">        </span><span style="color:#0086b3;">Ok</span><span style="color:#323232;">(T::from_str(</span><span style="color:#183691;">"1234"</span><span style="color:#323232;">);
</span><span style="color:#323232;">    }
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> my_conf_val </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Configuration::get();
</span><span style="color:#323232;">}
</span>
chrismit3s,

Well how do you want to use said get function?


<span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> x </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> config.</span><span style="color:#62a35c;">get</span><span style="color:#323232;">(</span><span style="color:#183691;">"key"</span><span style="color:#323232;">).await;
</span>

So what type should x have?

Turun,

I see two options immediately:

Make the function generic and return result(T, err), where T is the generic typed supplied by the caller (turbo fish syntax). Not sure if it will compile though.

Use whatever serve uses under the hood. They obviously have some way that allows them to return an arbitrary type. Alternatively implement it yourself by creating an enum that can be either string, int or bool. Will require matching by the caller after the function returns.

I know in e.g. java you regularly do if x.instanceof(y), but rust lends itself really badly to this type of programming.

Traister101,

Got yourself some interesting syntax there lol. It’s x instanceof Y

Ogeon, (edited )

It may be possible to use the https://doc.rust-lang.org/std/any/trait.Any.html trait to “launder” the value by first casting it to &amp;Any and then downcasting it to the generic type.


<span style="color:#323232;">let any_value = match tmp_value {
</span><span style="color:#323232;">    serde_json::Value::Number(x) => x as &amp;Any,
</span><span style="color:#323232;">    // ...
</span><span style="color:#323232;">};
</span><span style="color:#323232;">
</span><span style="color:#323232;">let maybe_value = any_value.downcast_ref::&lt; T >();
</span>

I haven’t tested it, so I may have missed something.

Edit: to be clear, this will not actually let you return multiple types, but let the caller decide which type to expect. I assumed this was your goal.

wulf,

Correct, I would want the caller to know what they’re getting, I’ll see if this works, Thank you!

I_like_cats,

No. You can only return a single type from the function. You could return the serde_json::Value though so that the code calling this function can get the value it needs itself

wulf,

Afraid this might have been the case, if Ogeon’s suggestion doesn’t work out, I’ll probably end up with multiple getters, one per type. There aren’t that many anyway

Thank you!

  • All
  • Subscribed
  • Moderated
  • Favorites
  • random
  • uselessserver093
  • Food
  • aaaaaaacccccccce
  • [email protected]
  • test
  • CafeMeta
  • testmag
  • MUD
  • RhythmGameZone
  • RSS
  • dabs
  • Socialism
  • KbinCafe
  • TheResearchGuardian
  • oklahoma
  • feritale
  • SuperSentai
  • KamenRider
  • All magazines