ฉันมีดังต่อไปนี้:
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}
" ในทั้งสามตัวอย่าง นี่เป็นประเภทที่ได้รับการแก้ไขบางส่วนซึ่งอาจสิ้นสุดf32
หรือf64
ขึ้นอยู่กับว่าคุณใช้งานอย่างไร “ {float}
” ไม่ใช่ชื่อประเภทตามกฎหมายมันเป็นตัวยึดความหมาย“ ฉันไม่แน่ใจว่าสิ่งนี้คืออะไร” แต่เป็นเลขทศนิยม ในกรณีที่เป็นตัวแปรทศนิยมถ้าคุณไม่ได้ จำกัด มันจะเริ่มต้นที่f64
¹ (ตัวอักษรจำนวนเต็มที่ไม่มีเงื่อนไขจะเป็นค่าเริ่มต้นi32
)
ดูสิ่งนี้ด้วย:
¹อาจยังมีวิธีการที่ทำให้งงงันคอมไพเลอร์เพื่อที่จะไม่สามารถตัดสินใจระหว่างf32
และf64
; ฉันไม่แน่ใจ. มันเคยเป็นเรื่องง่ายเหมือน32.90.eq(&32.90)
กัน แต่มันก็ปฏิบัติต่อทั้งสองอย่างในf64
ขณะนี้และเป็นไปอย่างมีความสุขดังนั้นฉันจึงไม่รู้
ImageBuffer<_, Vec<_>>
ที่ไม่ได้ช่วยฉันมากนักเมื่อฉันพยายามเขียนฟังก์ชั่นที่ใช้สิ่งเหล่านี้เป็นพารามิเตอร์ :()
และนี้เกิดขึ้นในรหัสที่มิฉะนั้นรวบรวมจนกว่าฉันจะเพิ่ม ไม่มีทางไหนที่ดีกว่านี้เหรอ?
มีฟังก์ชั่นที่ไม่เสถียรstd::intrinsics::type_name
ที่ทำให้คุณได้รับชื่อของประเภทถึงแม้ว่าคุณจะต้องใช้งานสร้างสนิมในยามค่ำคืน นี่คือตัวอย่าง:
#![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
เสถียรตั้งแต่เกิดสนิม 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"
}
}
//...
ไม่มี Intrisics หรือ nothin 'ดังนั้นแม้จะมีข้อ จำกัด มากขึ้นนี่เป็นทางออกเดียวที่ทำให้คุณได้รับสตริงและมีเสถียรภาพ (ดูคำตอบของ French Boiethios ) อย่างไรก็ตามมันลำบากมากและไม่ได้คำนึงถึงพารามิเตอร์ประเภทดังนั้นเราจึงสามารถ ...
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>"
}
นี่คือสิ่งที่ใช้เป็นการภายในเพื่อนำ{:?}
formatter ที่มีชื่อเสียงมาใช้
** อัพเดท ** สิ่งนี้ยังไม่ได้รับการยืนยันว่าทำงานได้ตลอดเวลาเมื่อเร็ว ๆ นี้
ฉันรวบรวมลังเล็กน้อยเพื่อทำสิ่งนี้ตามคำตอบของ 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
ไม่ได้ใช้งาน - นี่เป็นกรณีที่ไม่น่าเป็นไปได้ หนึ่งในสิ่งแรกที่คุณควรทำมากที่สุดใด ๆ struct #[derive(Debug)]
คือการเพิ่ม ฉันคิดว่าเวลาที่คุณไม่ต้องการDebug
มีขนาดเล็กมาก
println!("{:?}", unknown_var);
ไหม? มันคือการแก้ไขสตริง แต่ทำไม:?
ภายในวงเล็บปีกกา? @DenisKolodin
Debug
เพราะไม่ได้ใช้ แต่คุณสามารถใช้{}
เช่นกัน
มี @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)
หากคุณเพียงต้องการทราบประเภทของตัวแปรของคุณในระหว่างการพัฒนาเชิงโต้ตอบฉันขอแนะนำให้ใช้rls (เซิร์ฟเวอร์ภาษาสนิม) ในตัวแก้ไขหรือ IDE ของคุณ จากนั้นคุณสามารถเปิดใช้งานหรือสลับความสามารถของโฮเวอร์อย่างถาวรและวางเคอร์เซอร์ไว้เหนือตัวแปร ไดอะล็อกเล็ก ๆ น้อย ๆ ควรมีข้อมูลเกี่ยวกับตัวแปรรวมถึงประเภท
:?
มีมานานแล้วตอนนี้มีการใช้งานด้วยตนเอง แต่ที่สำคัญกว่านั้นstd::fmt::Debug
การนำไปใช้ (สำหรับการ:?
ใช้งานนั้น) สำหรับประเภทหมายเลขจะไม่มีคำต่อท้ายเพื่อระบุประเภทที่เป็นของมันอีกต่อไป