私は以下を持っています:
let mut my_number = 32.90;
タイプを印刷するにはどうすればよいmy_number
ですか?
使用type
して動作type_of
しませんでした。数値のタイプを印刷する別の方法はありますか?
私は以下を持っています:
let mut my_number = 32.90;
タイプを印刷するにはどうすればよいmy_number
ですか?
使用type
して動作type_of
しませんでした。数値のタイプを印刷する別の方法はありますか?
回答:
変数の型を見つけたいだけで、コンパイル時にそれを実行したい場合は、エラーを発生させて、コンパイラーに取得させることができます。
たとえば、変数を機能しないタイプに設定します。
let mut my_number: () = 32.90;
// let () = x; would work too
error[E0308]: mismatched types
--> src/main.rs:2:29
|
2 | let mut my_number: () = 32.90;
| ^^^^^ expected (), found floating-point number
|
= note: expected type `()`
found type `{float}`
または、無効なメソッドを呼び出します。
let mut my_number = 32.90;
my_number.what_is_this();
error[E0599]: no method named `what_is_this` found for type `{float}` in the current scope
--> src/main.rs:3:15
|
3 | my_number.what_is_this();
| ^^^^^^^^^^^^
let mut my_number = 32.90;
my_number.what_is_this
error[E0610]: `{float}` is a primitive type and therefore doesn't have fields
--> src/main.rs:3:15
|
3 | my_number.what_is_this
| ^^^^^^^^^^^^
これらはタイプを明らかにします。この場合、実際には完全には解決されていません。最初の例では「浮動小数点変数」と呼ば{float}
れ、3つすべての例では「」と呼ばれます。これは部分的に解決されたタイプであり、使用方法によっては、f32
またはになる可能性がありf64
ます。「{float}
」は有効な型名ではなく、「これが何であるかは完全にはわかりません」という意味のプレースホルダーですが、浮動小数点数です。浮動小数点変数の場合、制約しないと、デフォルトでf64
¹ になります。(修飾されていない整数リテラルはデフォルトでになりますi32
。)
以下も参照してください。
f32
andとの間で判断できないようにコンパイラを困惑させる方法がまだあるかもしれませんf64
。よく分かりません。以前はと同じくらい単純32.90.eq(&32.90)
でしたが、それはf64
今と同じように扱い、幸福にも満足しているので、わかりません。
ImageBuffer<_, Vec<_>>
これらのいずれかをパラメーターとして取る関数を記述しようとしているときに、どれがあまり役に立たないことを期待していることを教えてくれます。そしてこれは、私がを追加するまでコンパイルしないコードで発生します:()
。より良い方法はありませんか?
std::intrinsics::type_name
Rustのナイトリービルドを使用する必要がありますが、型の名前を取得できる不安定な関数があります(これは、安定したRustで動作することはほとんどありません)。次に例を示します。
#![feature(core_intrinsics)]
fn print_type_of<T>(_: &T) {
println!("{}", unsafe { std::intrinsics::type_name::<T>() });
}
fn main() {
print_type_of(&32.90); // prints "f64"
print_type_of(&vec![1, 2, 4]); // prints "std::vec::Vec<i32>"
print_type_of(&"foo"); // prints "&str"
}
#![feature(core_intrinsics)]
print_type_of
は&T
値(T
)ではなく参照()をとるので、&&str
ではなく渡す必要があり&str
ます。つまり、print_type_of(&"foo")
ではありませんprint_type_of("foo")
。
std::any::type_name
rust 1.38以降は安定しています:stackoverflow.com/a/58119924
std::any::type_name
関数を使用できます。これは毎晩のコンパイラーや外部クレートを必要とせず、結果はかなり正しいです:
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let s = "Hello";
let i = 42;
print_type_of(&s); // &str
print_type_of(&i); // i32
print_type_of(&main); // playground::main
print_type_of(&print_type_of::<i32>); // playground::print_type_of<i32>
print_type_of(&{ || "Hi!" }); // playground::main::{{closure}}
}
注意してください:ドキュメントで述べたように、この情報はデバッグ目的でのみ使用する必要があります。
これは診断用です。文字列の正確な内容と形式は、タイプのベストエフォートの説明であることを除いて、指定されていません。
タイプの表現をコンパイラのバージョン間で同じにしたい場合は、phicrの回答のように、特性を使用する必要があります。
すべてのタイプが事前にわかっている場合は、特性を使用してtype_of
メソッドを追加できます。
trait TypeInfo {
fn type_of(&self) -> &'static str;
}
impl TypeInfo for i32 {
fn type_of(&self) -> &'static str {
"i32"
}
}
impl TypeInfo for i64 {
fn type_of(&self) -> &'static str {
"i64"
}
}
//...
組み込みやnothinはありません。したがって、より限定的ではありますが、これは文字列を取得して安定させる唯一のソリューションです。(フランスのボイエチオスの答えを参照)しかし、それは非常に面倒であり、型パラメーターを考慮に入れていないので、...
trait TypeInfo {
fn type_name() -> String;
fn type_of(&self) -> String;
}
macro_rules! impl_type_info {
($($name:ident$(<$($T:ident),+>)*),*) => {
$(impl_type_info_single!($name$(<$($T),*>)*);)*
};
}
macro_rules! mut_if {
($name:ident = $value:expr, $($any:expr)+) => (let mut $name = $value;);
($name:ident = $value:expr,) => (let $name = $value;);
}
macro_rules! impl_type_info_single {
($name:ident$(<$($T:ident),+>)*) => {
impl$(<$($T: TypeInfo),*>)* TypeInfo for $name$(<$($T),*>)* {
fn type_name() -> String {
mut_if!(res = String::from(stringify!($name)), $($($T)*)*);
$(
res.push('<');
$(
res.push_str(&$T::type_name());
res.push(',');
)*
res.pop();
res.push('>');
)*
res
}
fn type_of(&self) -> String {
$name$(::<$($T),*>)*::type_name()
}
}
}
}
impl<'a, T: TypeInfo + ?Sized> TypeInfo for &'a T {
fn type_name() -> String {
let mut res = String::from("&");
res.push_str(&T::type_name());
res
}
fn type_of(&self) -> String {
<&T>::type_name()
}
}
impl<'a, T: TypeInfo + ?Sized> TypeInfo for &'a mut T {
fn type_name() -> String {
let mut res = String::from("&mut ");
res.push_str(&T::type_name());
res
}
fn type_of(&self) -> String {
<&mut T>::type_name()
}
}
macro_rules! type_of {
($x:expr) => { (&$x).type_of() };
}
それを使ってみましょう:
impl_type_info!(i32, i64, f32, f64, str, String, Vec<T>, Result<T,S>)
fn main() {
println!("{}", type_of!(1));
println!("{}", type_of!(&1));
println!("{}", type_of!(&&1));
println!("{}", type_of!(&mut 1));
println!("{}", type_of!(&&mut 1));
println!("{}", type_of!(&mut &1));
println!("{}", type_of!(1.0));
println!("{}", type_of!("abc"));
println!("{}", type_of!(&"abc"));
println!("{}", type_of!(String::from("abc")));
println!("{}", type_of!(vec![1,2,3]));
println!("{}", <Result<String,i64>>::type_name());
println!("{}", <&i32>::type_name());
println!("{}", <&str>::type_name());
}
出力:
i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str
UPD以下は動作しなくなりました。Shubhamの回答を確認するをして修正してください。
チェックしてくださいstd::intrinsics::get_tydesc<T>()
。現在は「実験的」な状態ですが、型システムをハッキングしているだけでも問題ありません。
次の例を確認してください。
fn print_type_of<T>(_: &T) -> () {
let type_name =
unsafe {
(*std::intrinsics::get_tydesc::<T>()).name
};
println!("{}", type_name);
}
fn main() -> () {
let mut my_number = 32.90;
print_type_of(&my_number); // prints "f64"
print_type_of(&(vec!(1, 2, 4))); // prints "collections::vec::Vec<int>"
}
**更新**これは最近動作することが確認されていません。
私はvboの答えに基づいてこれを行うために小さな箱をまとめました。それはあなたにタイプを返すか印刷するマクロを与えます。
これをCargo.tomlファイルに入れます。
[dependencies]
t_bang = "0.1.2"
その後、次のように使用できます。
#[macro_use] extern crate t_bang;
use t_bang::*;
fn main() {
let x = 5;
let x_type = t!(x);
println!("{:?}", x_type); // prints out: "i32"
pt!(x); // prints out: "i32"
pt!(5); // prints out: "i32"
}
#![feature]
安定版リリースチャネルでは使用できない可能性があります
で変数を使用するという簡単なアプローチも使用できますprintln!("{:?}", var)
。Debug
タイプに実装されていない場合は、コンパイラのエラーメッセージでタイプを確認できます。
mod some {
pub struct SomeType;
}
fn main() {
let unknown_var = some::SomeType;
println!("{:?}", unknown_var);
}
(プレイペン)
汚れていますが動作します。
Debug
実装されていない -とはいえ、これはかなり低い場合です。ほとんどの構造体に対して最初に行うべきことの1つはadd #[derive(Debug)]
です。あなたが欲しくない時Debug
は非常に少ないと思います。
println!("{:?}", unknown_var);
か説明できますか?それは文字列補間:?
ですか?なぜ中括弧の内側ですか?@DenisKolodin
Debug
実装されていないので使用し{}
ましたが、使用することもできます。
安定した錆の近似タイプ( "float")を取得するための@ChrisMorgan 回答があり、@ ShubhamJain 回答があります毎晩錆で不安定な関数を使用して正確なタイプ(「F64」)を取得するには。
これが、安定した錆の中で正確な型を取得する(つまり、f32とf64のどちらにするか)方法です。
fn main() {
let a = 5.;
let _: () = unsafe { std::mem::transmute(a) };
}
結果は
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> main.rs:3:27
|
3 | let _: () = unsafe { std::mem::transmute(a) };
| ^^^^^^^^^^^^^^^^^^^
|
= note: source type: `f64` (64 bits)
= note: target type: `()` (0 bits)
更新
ターボフィッシュのバリエーション
fn main() {
let a = 5.;
unsafe { std::mem::transmute::<_, ()>(a) }
}
少し短くなりますが、読みにくくなります。
float
間で伝える、f32
とf64
して達成することができますstd::mem::size_of_val(&a)
他のいくつかの回答は機能しませんが、typenameのクレートは機能します。
新しいプロジェクトを作成します。
cargo new test_typename
Cargo.tomlを変更する
[dependencies]
typename = "0.1.1"
ソースコードを修正する
use typename::TypeName;
fn main() {
assert_eq!(String::type_name(), "std::string::String");
assert_eq!(Vec::<i32>::type_name(), "std::vec::Vec<i32>");
assert_eq!([0, 1, 2].type_name_of(), "[i32; 3]");
let a = 65u8;
let b = b'A';
let c = 65;
let d = 65i8;
let e = 65i32;
let f = 65u32;
let arr = [1,2,3,4,5];
let first = arr[0];
println!("type of a 65u8 {} is {}", a, a.type_name_of());
println!("type of b b'A' {} is {}", b, b.type_name_of());
println!("type of c 65 {} is {}", c, c.type_name_of());
println!("type of d 65i8 {} is {}", d, d.type_name_of());
println!("type of e 65i32 {} is {}", e, e.type_name_of());
println!("type of f 65u32 {} is {}", f, f.type_name_of());
println!("type of arr {:?} is {}", arr, arr.type_name_of());
println!("type of first {} is {}", first, first.type_name_of());
}
出力は次のとおりです。
type of a 65u8 65 is u8
type of b b'A' 65 is u8
type of c 65 65 is i32
type of d 65i8 65 is i8
type of e 65i32 65 is i32
type of f 65u32 65 is u32
type of arr [1, 2, 3, 4, 5] is [i32; 5]
type of first 1 is i32
typename
宣言の中で明示的な型なしの変数では動作しません。それを実行するmy_number
質問は以下のエラーを与えるから「メソッドを呼び出すことはできませんtype_name_of
あいまいな数値タイプに{float}
。ヘルプ:あなたはこの結合のためのタイプを指定する必要があり、同様にf32
」
0.65
、それはうまくいきます:type of c 0.65 0.65 is f64
。これが私のバージョンです:rustc 1.38.0-nightly (69656fa4c 2019-07-13)
:?
かなり長い間、今では手動で実装されています。しかし、より重要なこととして、数値型のstd::fmt::Debug
実装(それが:?
使用するもの)には、それがどの型であるかを示すサフィックスが含まれなくなりました。