আমি কীভাবে মরিচায় একটি চলকের ধরণ প্রিন্ট করব?


237

আমার নিম্নলিখিতগুলি রয়েছে:

let mut my_number = 32.90;

আমি কীভাবে প্রিন্ট করব my_number?

ব্যবহার typeএবং type_ofকাজ করে নি। আমি নম্বর টাইপ মুদ্রণ করতে পারেন অন্য কোন উপায় আছে?

উত্তর:


177

আপনি নিছক করতে চান জানতে একটি পরিবর্তনশীল ধরণ এবং কম্পাইল সময়ে এটা করতে ইচ্ছুক হয়, আপনি একটি ত্রুটি কারণ এবং এটা নিতে কম্পাইলার পেতে পারেন।

উদাহরণস্বরূপ, ভেরিয়েবলটিকে এমন ধরণের সেট করুন যা কাজ করে না :

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))

আরো দেখুন:


Still এখনও সংকলককে হতবাক করার উপায় রয়েছে যাতে এটি f32এবং এর মধ্যে সিদ্ধান্ত নিতে পারে না f64; আমি নিশ্চিত নই. এটি এতটা সহজ হিসাবে ব্যবহৃত হত 32.90.eq(&32.90)তবে এটি f64এখনকার মতোই আচরণ করে এবং খুশির সাথে চাগে, তাই আমি জানি না।


4
:?দীর্ঘদিন ধরে এখন ম্যানুয়ালি প্রয়োগ করা হয়েছে। তবে আরও বড় কথা, সংখ্যার প্রকারের std::fmt::Debugজন্য প্রয়োগকরণ (এর জন্য এটিই :?ব্যবহার করে) কোন ধরণের এটি বোঝাতে একটি প্রত্যয় যুক্ত করা হয় না।
ক্রিস মরগ্যান

2
আমি কোনও এক্সপ্রেশনের ধরণের সন্ধান করার জন্য এই কৌশলগুলি প্রচুর ব্যবহার করি তবে এটি সর্বদা কার্যকর হয় না, বিশেষত যখন টাইপ পরামিতিগুলি জড়িত থাকে। সংকলক, উদাহরণস্বরূপ, আমাকে বলবে যে এটি এমন ImageBuffer<_, Vec<_>>একটির প্রত্যাশা করে যা আমাকে খুব একটা সহায়তা করে না যখন আমি কোনও ফাংশন লেখার চেষ্টা করছি যা এই বিষয়গুলির মধ্যে একটিকে প্যারামিটার হিসাবে নেয়। এবং কোডে এটি ঘটে যা অন্যথায় আমি সংযুক্ত না হওয়া পর্যন্ত সংকলন করে :()। এর চেয়ে ভাল আর কোন উপায় নেই?
ক্রিস্টোফার আর্মস্ট্রং

2
এটি কিছুটা বিশৃঙ্খলাবদ্ধ এবং অযৌক্তিক বলে মনে হচ্ছে। কোড সম্পাদকের পক্ষে কি খুব কঠিন হয়ে উঠবে যেমন অন্যান্য অনেক ভাষার মতো কার্সার চলকটির উপরে স্থির থাকে তখন ইমাকগুলি প্রকারটি সরবরাহ করে? সংকলক যদি ত্রুটির উপরের ধরণটি বলতে পারে, তবে কোনও ত্রুটি না থাকলে অবশ্যই এটি টাইপটি ইতিমধ্যে জানা উচিত?
xji

1
@ জিক্সিয়াং: মরিচা ল্যাঙ্গুয়েজ সার্ভারটি আইডিইতে এই তথ্য সরবরাহের বিষয়ে সমস্ত কিছুই, তবে এটি এখনও পরিপক্ক নয় — এর প্রথম আলফা প্রকাশটি কয়েক দিন আগেই হয়েছিল। হ্যাঁ, এটি একটি প্রবীণ পদ্ধতি; হ্যাঁ, লক্ষ্য অর্জনের কম অদ্ভুত উপায় অবিচ্ছিন্নভাবে আসছে।
ক্রিস মরগান

1
এই খুব হ্যাক মত শোনাচ্ছে। কোনও ভেরিয়েবলের ধরণটি পরীক্ষা করার জন্য এটি কি আসলেই মূ ?় উপায়?
বিভ্রান্ত

109

একটি অস্থির ফাংশন রয়েছে 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"
}

@ ভিবো: স্থির না হওয়া পর্যন্ত নয় এরকম কিছু বেশিরভাগ সময় স্থিতিশীল হওয়ার সম্ভাবনা নেই, যদি কখনও হয় — এবং এটি কখনই স্থিতিশীল না হয় তবে তা আমাকে অবাক করে না; এটি আপনার পছন্দসই কাজটি করা উচিত নয়।
ক্রিস মরগ্যান

2
মরিচা-রাত্রে (1.3) এ কেবল তখনই কাজ হয়েছিল যখন সেই প্রথম লাইনটি পরিবর্তিত হবে#![feature(core_intrinsics)]
এটি

1
@DmitriNesteruk: print_type_ofরেফারেন্স (নিচ্ছে &T), না মান ( T,) যাতে আপনি পাস করতে হবে &&strবরং &str; যে, print_type_of(&"foo")বরং print_type_of("foo")
ক্রিস মরগান

আপনি ঠিক বলেছেন, 3 বছর কেটে গেছে এবং এটি এখনও স্থিতিশীল নয়।
আন্তন কোচকভ

5
std::any::type_nameমরিচা 1.38 সাল থেকে স্থিতিশীল: stackoverflow.com/a/58119924
টিম রবিনসন

66

আপনি 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}}
}

সতর্কতা অবলম্বন করুন: ডকুমেন্টেশনে যেমন বলা হয়েছে, এই তথ্যটি কেবল একটি ডিবাগ উদ্দেশ্যেই ব্যবহার করা উচিত:

এটি ডায়াগনস্টিক ব্যবহারের জন্য তৈরি। স্ট্রিংয়ের সঠিক বিষয়বস্তু এবং ফর্ম্যাটটি নির্দিষ্ট নয়, ধরণের সর্বোত্তম প্রচেষ্টা বর্ণনা থাকা ছাড়া অন্য।

আপনি যদি সংকলক সংস্করণগুলির মধ্যে আপনার টাইপের প্রতিনিধিত্ব একইরকম রাখতে চান তবে আপনার ফিকারের উত্তরের মতো একটি বৈশিষ্ট্য ব্যবহার করা উচিত ।


1
আমার পক্ষে সেরা উত্তর, কারণ বেশিরভাগ ডেভসগুলি ডিবাগিং উদ্দেশ্যে যেমন ছাপার ব্যর্থতা ব্যর্থতার জন্য এটি ব্যবহার করতে চায়
কায়সার

ঠিক আমার যা প্রয়োজন, আমি জানি না কেন এটি চিহ্নিত উত্তর নয়!
জেমস পোলুস

1
@ জেমসপলুস কারণ এই ফাংশনটি সাম্প্রতিক তাই আমার উত্তরটি আরও নতুন।
বোয়িথিওস

53

আপনি যদি আগে থেকে সমস্ত প্রকারগুলি জানেন তবে আপনি কোনও 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"
    }
}

//...

কোনও ইন্ট্রিসিক বা নটিন 'নয়, সুতরাং আরও সীমাবদ্ধ হলেও এটি এখানে একমাত্র সমাধান যা আপনাকে স্ট্রিং দেয় এবং স্থিতিশীল। ( ফরাসি বোয়েথিয়সের উত্তর দেখুন ) তবে এটি অত্যন্ত শ্রমসাধ্য এবং প্রকারের পরামিতিগুলির জন্য অ্যাকাউন্ট করে না, তাই আমরা ...

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

মরিচা খেলার মাঠ


এই উত্তর দুটি পৃথক উত্তর মধ্যে বিভক্ত হতে পারে যাতে দুটি মিশ্রণ এড়ানোর জন্য।
প্রজওয়াল ধাওয়ালিয়া

2
@ প্রজ্বালধাওয়ালিয়া আপনি যা বলেছিলেন সে সম্পর্কে আমি ভাবছিলাম এবং সংস্করণগুলি একে অপরের পরিপূরক হিসাবে আমি সন্তুষ্ট বলে মনে করি। বৈশিষ্ট্য সংস্করণটি ম্যাক্রো সংস্করণটি হুডের নীচে কী করছে তার একটি সরলকরণ দেখায় এবং এর লক্ষ্যগুলি আরও স্পষ্ট করে তোলে। অন্যদিকে ম্যাক্রো সংস্করণটি দেখায় যে কীভাবে বৈশিষ্ট্য সংস্করণটিকে আরও সাধারণভাবে ব্যবহারযোগ্য করে তোলা যায়; এটি করার একমাত্র উপায় নয়, এমনকি এটি দেখানোও সুবিধাজনক। সংক্ষেপে, এটি দুটি উত্তর হতে পারে তবে আমি অনুভব করি পুরোটি তার অংশগুলির যোগফলের চেয়ে বড়।
ফিকার

19

ইউপিডি নিম্নলিখিতটি আর কাজ করে না। সংশোধনের জন্য শুভমের উত্তর পরীক্ষা করে দেখুন ।

চেক আউট 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>"
}

এই হল এটা কি অভ্যন্তরীণভাবে ব্যবহৃত বিখ্যাত বাস্তবায়ন {:?}ফরম্যাটার।


15

** আপডেট ** সম্প্রতি কোনও সময় কাজ করার জন্য এটি যাচাই করা হয়নি।

আমি vbo এর উত্তর ভিত্তিক এটি করতে একটি সামান্য ক্রেট লাগিয়েছি। এটি আপনাকে টাইপটি ফিরে আসতে বা মুদ্রণ করতে একটি ম্যাক্রো দেয়।

এটি আপনার কার্গো.টমল ফাইলে রাখুন:

[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"
}

@vbo বলেছেন যে তার সমাধানটি আর কাজ করে না। তোমার কি কাজ?
অ্যান্টনি হ্যাচকিন্স 14'19

কাজ করছে না `ত্রুটি [E0554]: #![feature]স্থিতিশীল রিলিজ চ্যানেলে ব্যবহার করা যেতে পারে না`
মুহাম্মাদ

7

আপনি ভেরিয়েবলটি ইন-এর সহজ পদ্ধতির ব্যবহার করতে পারেন println!("{:?}", var)। যদি Debugএই ধরণের জন্য প্রয়োগ না করা হয় তবে আপনি সংকলকের ত্রুটি বার্তায় টাইপটি দেখতে পাবেন:

mod some {
    pub struct SomeType;
}

fn main() {
    let unknown_var = some::SomeType;
    println!("{:?}", unknown_var);
}

( প্লেপেইন )

এটি নোংরা কিন্তু এটি কাজ করে।


8
যদি Debugপ্রয়োগ না করা হয় - তবে এটি বেশ সম্ভাবনাময় ঘটনা। যে কোনও স্ট্রাক্টের জন্য আপনাকে প্রথমে করণীয় হ'ল অ্যাড #[derive(Debug)]। আমার মনে হয় আপনি যে সময়গুলি চান না তা Debugখুব অল্প হয়।
শেপমাস্টার

1
কি ঘটছে তা আপনি ব্যাখ্যা করতে পারবেন println!("{:?}", unknown_var);?? এটি কি স্ট্রিং ইন্টারপোলেশন তবে :?কোঁকড়ানো বন্ধনীগুলির ভিতরে কেন ? @ ডেনিসকলোডিন
জুলিও মেরিনস

আমি ত্রুটি উত্সাহিত। সংকলকটি ত্রুটির সাথে ধরণের তথ্য সরবরাহ করার ধারণা। আমি ব্যবহার করেছি Debugকারণ এটি বাস্তবায়িত হয়নি, তবে আপনি এটিও ব্যবহার করতে পারেন {}
ডেনিসকলোডিন

4

একটা @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)
অ্যান্টনি হ্যাচকিনস

1

কিছু অন্যান্য উত্তর কাজ করে না, তবে আমি পাই যে টাইপনেম ক্রেট কাজ করে।

  1. একটি নতুন প্রকল্প তৈরি করুন:

    cargo new test_typename
  2. কার্গো.টমল সংশোধন করুন

    [dependencies]
    typename = "0.1.1"
  3. আপনার উত্স কোডটি পরিবর্তন করুন

    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"
অ্যান্টনি Hatchkins

আমি পরীক্ষা 0.65এবং এটি ভাল কাজ করে: type of c 0.65 0.65 is f64। এখানে আমার সংস্করণটি রয়েছে:rustc 1.38.0-nightly (69656fa4c 2019-07-13)
ফ্লাইক

1

ইন্টারেক্টিভ বিকাশের সময় যদি আপনি কেবল আপনার পরিবর্তনশীলের প্রকারটি জানতে চান তবে আমি আপনার সম্পাদক বা আদর্শের অভ্যন্তরে rls (মরিচা ভাষা সার্ভার) ব্যবহার করার পরামর্শ দেব । তারপরে আপনি কেবল স্থায়ীভাবে সক্ষম বা টানুন হোভারের ক্ষমতা এবং কেবল আপনার কার্সারটিকে ভেরিয়েবলের উপরে রেখে দিতে পারেন। একটু সংলাপে টাইপ সহ ভেরিয়েবল সম্পর্কে তথ্য উপস্থিত করা উচিত।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.