কেবল কোনও চলনযোগ্য এবং অনুলিপিযোগ্য নয় এমন কোনও ধরণের তৈরি করা কি সম্ভব?


96

সম্পাদকের দ্রষ্টব্য : এই প্রশ্নটি মরিচা ০.০ এর আগে জিজ্ঞাসা করা হয়েছিল এবং প্রশ্নটিতে কিছু দৃser়তা অবশ্যই মরিচা ১.০ এ সত্য নয়। উভয় সংস্করণ সম্বোধন করতে কিছু উত্তর আপডেট করা হয়েছে।

আমার এই স্ট্রাক্ট আছে

struct Triplet {
    one: i32,
    two: i32,
    three: i32,
}

যদি আমি এটি কোনও ফাংশনে পাস করি তবে এটি স্পষ্টভাবে অনুলিপি করা হয়। এখন, কখনও কখনও আমি পড়ি যে কিছু মান কপিযোগ্য নয় এবং তাই সরানো হয়েছে।

এই স্ট্রাক্টটি Tripletঅনুলিপিযোগ্য করা কি সম্ভব হবে ? উদাহরণস্বরূপ, এমন কোনও বৈশিষ্ট্য কার্যকর করা সম্ভব হবে যা Tripletঅনুলিপিযোগ্য এবং সেইজন্য "চলমান" হয়ে উঠবে ?

আমি কোথাও পড়েছি যে Cloneস্পষ্টত অনুলিপিযোগ্য নয় এমন জিনিসগুলি অনুলিপি করার জন্য কারও বৈশিষ্ট্যটি প্রয়োগ করতে হবে , তবে আমি অন্যদিকে কখনও পড়িনি, এটি এমন কিছু যা স্পষ্টতই অনুলিপিযোগ্য এবং অন-অনুলিপিযোগ্য করে তোলে যাতে এটি পরিবর্তে চলে।

এটি কি কোনও অর্থবোধ করে?


4
paulkoerbitz.de/posts/… । বনাম অনুলিপি চলুন কেন এখানে ভাল ব্যাখ্যা ।
শান পেরি

উত্তর:


165

ভূমিকা : এই উত্তরটি আগে লেখা হয়েছিল অপ্ট ইন বিল্ট-ইন বৈশিষ্ট্যগুলো -specifically দিক বাস্তবায়িত -were। আমি কেবল পুরানো স্কিমের ক্ষেত্রে প্রয়োগ করা বিভাগগুলি চিহ্নিত করতে ব্লক কোট ব্যবহার করেছি (প্রশ্নটি যখন জিজ্ঞাসা করার সময় প্রয়োগ হয়েছিল)।Copy


পুরানো : মৌলিক প্রশ্নের উত্তর দিতে, আপনি একটি NoCopyমান সংরক্ষণ করে একটি চিহ্নিতকারী ক্ষেত্র যুক্ত করতে পারেন । যেমন

struct Triplet {
    one: int,
    two: int,
    three: int,
    _marker: NoCopy
}

আপনি এটি একটি ডেস্ট্রাক্টর ( Dropবৈশিষ্ট্য প্রয়োগের মাধ্যমে ) করেও করতে পারেন , তবে যদি ডেস্ট্রাক্টর কিছু না করে তবে চিহ্নিতকারী প্রকারগুলি ব্যবহার করা পছন্দ হয়।

প্রকারগুলি এখন ডিফল্টরূপে সরানো হয়, এটি হ'ল আপনি যখন কোনও নতুন প্রকারের সংজ্ঞা দেন তখন এটি কার্যকর হয় না Copyযতক্ষণ না আপনি স্পষ্টভাবে আপনার ধরণের জন্য এটি প্রয়োগ করেন:

struct Triplet {
    one: i32,
    two: i32,
    three: i32
}
impl Copy for Triplet {} // add this for copy, leave it out for move

বাস্তবায়ন কেবল তখনই বিদ্যমান থাকতে পারে যদি নতুনটিতে থাকা প্রতিটি প্রকার structবা enumনিজেই থাকে Copy। যদি তা না হয় তবে সংকলক একটি ত্রুটি বার্তা প্রিন্ট করবে। টাইপটির যদি বাস্তবায়ন না হয় কেবল তখনই এটি বিদ্যমান থাকতে পারে Drop


যে প্রশ্নটি আপনি জিজ্ঞাসা করেননি তার জবাব দিতে ... "চাল এবং অনুলিপি নিয়ে কী আছে?":

প্রথমে আমি দুটি পৃথক "অনুলিপি" সংজ্ঞায়িত করব:

  • একটি বাইট অনুলিপি , যা কেবল অল্প মাত্রায় কোনও বাইট-বাই-বাইট কোনও বিষয়বস্তু অনুলিপি করছে , নিম্নলিখিত পয়েন্টারগুলি নয়, উদাহরণস্বরূপ যদি আপনার কাছে থাকে তবে (&usize, u64)এটি একটি 64-বিট কম্পিউটারে 16 বাইট, এবং একটি অগভীর অনুলিপি 16 বাইট নিবে এবং তার প্রতিলিপি করবে মেমরি কিছু অন্যান্য 16-বাইট খণ্ড মান, ছাড়া স্পর্শ usizeএর অন্য প্রান্তে &। এটি, কল করার সমতুল্য memcpy
  • একটি শব্দার্থক অনুলিপি , একটি নতুন (কিছুটা) স্বতন্ত্র উদাহরণ তৈরির জন্য একটি মানটিকে নকল করে যা পুরানোটির সাথে আলাদাভাবে ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, কোনওটির শব্দার্থক অনুলিপি Rc<T>কেবলমাত্র রেফারেন্স গণনা বাড়িয়ে তোলে এবং এর একটি শব্দার্থক অনুলিপি Vec<T>একটি নতুন বরাদ্দ তৈরি করা জড়িত, এবং তারপরে সিন্থেটিকভাবে প্রতিটি সঞ্চিত উপাদানকে পুরানো থেকে নতুন করে অনুলিপি করে। এগুলি গভীর অনুলিপি হতে পারে (উদাঃ Vec<T>) বা অগভীর (উদাহরণস্বরূপ Rc<T>সঞ্চিত স্পর্শ করে না T), Cloneকোনওভাবে Tভিতরে থেকে কোনও ধরণের মানকে শব্দার্থভাবে অনুলিপি করতে প্রয়োজনীয় ক্ষুদ্রতম কাজের হিসাবে স্বল্পভাবে সংজ্ঞায়িত &Tহয় T

মরিচা সি এর মতো, একটি মানের প্রতিটি বাই-মান ব্যবহার একটি বাইট অনুলিপি:

let x: T = ...;
let y: T = x; // byte copy

fn foo(z: T) -> T {
    return z // byte copy
}

foo(y) // byte copy

এগুলি বাইট অনুলিপিগুলি হয় না তা Tসরানো হয় বা "অন্তর্নিহিত অনুলিপিযোগ্য"। (স্পষ্টরূপে বলতে গেলে, রান-টাইমে এগুলি অগত্যা আক্ষরিক অর্থে বাই বাইট কপি নয়: সংকলক কোডের আচরণ সংরক্ষণ করা থাকলে অনুলিপিগুলি অনুলিপি করতে মুক্ত to)

যাইহোক, বাইট অনুলিপিগুলির সাথে একটি মৌলিক সমস্যা রয়েছে: আপনি মেমরিতে নকল মানগুলি দিয়ে শেষ করেন, এটির ডেস্ট্রাক্টর থাকলে খুব খারাপ হতে পারে eg

{
    let v: Vec<u8> = vec![1, 2, 3];
    let w: Vec<u8> = v;
} // destructors run here

যদি wকেবল একটি সাধারণ বাইট অনুলিপি হয় vতবে সেখানে দু'জন ভেক্টর একই বরাদ্দের দিকে ইশারা করত, উভয়ই এটির মুক্তকারী ধ্বংসকারীদের সাথে ... ডাবল ফ্রি তৈরি করে যা একটি সমস্যা। এনবি। এই পুরোপুরি ঠিক হয়ে যাব যদি আমরা একটি শব্দার্থিক কপি করেছিল vমধ্যে w, যেহেতু তারপর wনিজস্ব স্বাধীন হবে Vec<u8>এবং destructors একে অপরের ওপর পদদলিত করা হবে না।

এখানে কয়েকটি সম্ভাব্য সমাধান রয়েছে:

  • প্রোগ্রামারটিকে সি এর মতো এটি পরিচালনা করতে দিন (সি তে কোনও ধ্বংসকারী নেই, সুতরাং এটি ততটা খারাপ নয় ... পরিবর্তে আপনি কেবল মেমরি ফাঁস দিয়ে রেখে যান:: পি)
  • অন্তর্নিহিতভাবে একটি শব্দার্থক অনুলিপি সম্পাদন করুন, যাতে wএর নিজস্ব বরাদ্দ রয়েছে, যেমন এর অনুলিপি নির্মাণকারীদের সাথে সি ++।
  • মালিকানার স্থানান্তর হিসাবে বাই-মান ব্যবহারগুলি সম্মান করুন, যাতে এটি vআর ব্যবহার করা যায় না এবং এর ডেস্ট্রাক্টর চালিত না হয়।

শেষটি যা মরিচা করে: একটি পদক্ষেপ কেবলমাত্র একটি মান অনুসারে ব্যবহার যেখানে উত্সটি স্থিতিশীলভাবে অবৈধ হয়, তাই সংকলকটি এখন-অবৈধ মেমরির আরও ব্যবহারকে বাধা দেয়।

let v: Vec<u8> = vec![1, 2, 3];
let w: Vec<u8> = v;
println!("{}", v); // error: use of moved value

যে ধরণের ডেস্ট্রাক্টর রয়েছে তাদের অবশ্যই বাই-মান (যখন বাইট অনুলিপি করা হয়) ব্যবহার করার সময় চলতে হবে , যেহেতু তাদের কিছু সংস্থান (যেমন একটি মেমরি বরাদ্দ, বা একটি ফাইল হ্যান্ডেল) এর মালিকানা / মালিকানা রয়েছে এবং এটির খুব সম্ভবত সম্ভাবনা নেই যে বাইট অনুলিপিটি এটি সঠিকভাবে নকল করবে মালিকানা

"আচ্ছা ... একটি অন্তর্নিহিত অনুলিপি কি?"

আদিম ধরণের সম্পর্কে চিন্তা করুন u8: একটি বাইট অনুলিপি সহজ, কেবল একক বাইট অনুলিপি করুন, এবং একটি শব্দার্থক অনুলিপি ঠিক তত সহজ, একক বাইট অনুলিপি করুন। বিশেষ করে, একটি বাইট কপি হয় একটি শব্দার্থিক কপি ... মরচে এমনকি রয়েছে বিল্ট-ইন বৈশিষ্ট্যCopy যে যেমনটি কোন ধরনের অভিন্ন শব্দার্থিক এবং বাইট কপি আছে।

সুতরাং, এই Copyধরণের বাই-মান ব্যবহারগুলি স্বয়ংক্রিয়ভাবে শব্দার্থক অনুলিপিগুলিও তাই উত্সটি ব্যবহার করা চালিয়ে যাওয়া নিরাপদ।

let v: u8 = 1;
let w: u8 = v;
println!("{}", v); // perfectly fine

পুরাতন : NoCopyচিহ্নিতকারীটি ধরণের Copy(যেমন কেবল আদিমদের সমষ্টি এবং &) যেগুলি হতে পারে তা ধরে নিয়ে সংযোজকটির স্বয়ংক্রিয় আচরণকে ওভাররাইড করে Copy। তবে অন্তর্নির্মিত বৈশিষ্ট্যগুলি অপ্ট-ইন করার সময় এটি পরিবর্তন হবে ।

উপরে উল্লিখিত হিসাবে, অন্তর্নির্মিত বৈশিষ্ট্যগুলি অপ্ট-ইন করা হয়, তাই সংকলকটির আর স্বয়ংক্রিয় আচরণ নেই। তবে অতীতে স্বয়ংক্রিয় আচরণের জন্য ব্যবহৃত বিধিটি প্রয়োগ করা বৈধ কিনা তা যাচাই করার জন্য একই নিয়ম Copy


@ ডাবউপ: আপনি কি জাস্ট জাস্টটির কোন সংস্করণে অন্তর্নির্মিত বৈশিষ্ট্যগুলি বেছে নিয়েছেন? আমি 0.10 মনে করি।
ম্যাথিউ এম।

নিবন্ধন করুন এটি এখনও কার্যকর করা হয়নি এবং সম্প্রতি বিল্ট-ইনগুলি অপ্ট-ইন করার নকশায় কিছু প্রস্তাবিত সংশোধন হয়েছে
হুন

আমি মনে করি যে পুরানো উক্তিটি মুছে ফেলা উচিত।
স্টারগেটর

4
# [উত্পন্ন (অনুলিপি, ক্লোন)]
ট্রিপলেটটিতে

6

সবচেয়ে সহজ উপায় হ'ল আপনার প্রকারের এমন কিছু এম্বেড করা যা অনুলিপিযোগ্য নয়।

মানক গ্রন্থাগারটি ঠিক এই ব্যবহারের ক্ষেত্রে "মার্কার ধরণের" সরবরাহ করে: নোকপি । উদাহরণ স্বরূপ:

struct Triplet {
    one: i32,
    two: i32,
    three: i32,
    nocopy: NoCopy,
}

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