How to store an invariant type variable in Rust

时光毁灭记忆、已成空白 提交于 2020-07-10 06:46:27

问题


I would like to parse the type of each value in a row of data from tokio-postgresql

Here is an example of getting a single value for a row of data from postgresql:

...
let rows = client
   .query("select * from ExampleTable;")
   .await?;

// This is how you read a string if you know the first column is a string type.
let thisValue: &str = rows[0].get(0);

In this example, it is known at design-time that the type in the first column is a string, and therefore the type for thisValue is &str. I would like to accept an invariant type.

I intend to use std::any::type_name::<T>() to derive the type name in thisValue and then use conditional logic (if/switch) to process this data differently depending on the type.

Is there an invariant way to store a variable in Rust? Will std::any::type_name::<T>() work on that variable? Is there another way to "box" the variable instead?

I understand that std::any::type_name::<T>() is using a kind of generics interface. To me, this means it's probably a compile-time strategy, not run-time. So I have my doubts that the way I am researching will work, but I hope I am on the right track and only need the final piece: an invariant type.

Should I be using &dyn Any and TypeId::of::<TypeHere>() == thisValue.type_id()?

In this situation, the get function of this API tokio-postgresql uses generics and doesn't return a boxed value. Therefore in this situation I may need to use columns() to determine the Rust type and the use separate functions to call get with different variables types.

The overall question still needs to be answered "How to store an invariant type variable in Rust", regardless of the specifics I have used to ask the title question.


回答1:


  1. The preferred invariant type is &dyn any

With &dyn any: any is the trait, dyn means the type of the trait.

Declaring:

let thisValue: &dyn Any = rows[0].get(0); //This works if tokio-postgresql returned a "dyn any" type, which it doesn't

Example of testing what type is referenced:

TypeId::of::<String>() == thisValue.type_id() //type checking using TypeId of boxed value.

Example of testing the type with downcast:

if let Some(string) = thisValue.downcast_ref::<String>() {
    println!("String ({}): {}", string.len(), string);
}
  1. Boxed

Box to force heap allocation (if necessary). This strategy is included too, so you can see how &dyn Any works with Boxed

A "boxed" value of dyn Any is invariant:

let thisValue: Boxed<dyn Any> = rows[0].get(0);  //This works if tokio-postgresql returned a "dyn any" type, which it doesn't

In this scenario the API being used requires generic inference, so for tokio-postgresql this won't work, but it is the answer for the title question.

An example of testing the type with the downcast function of Boxed:

if let Ok(string) = thisValue.downcast::<String>() {
    println!("String ({}): {}", string.len(), string);
}

About the postgresql sub-problem

As per the original post,

In this situation, the get function of this API tokio-postgresql uses generics and doesn't return a boxed value. Therefore in this situation I may need to use columns() to determine the Rust type and the use separate functions to call get with different variables types.

So this answer solves the question, and although it won't work with the tokio-postgresql API, it equips you with the knowledge of the kind of API you would like to find/build/wait-for.



来源:https://stackoverflow.com/questions/62749560/how-to-store-an-invariant-type-variable-in-rust

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!