গো ইন্টারফেসের থেকে মরিচা বৈশিষ্ট্যগুলি কীভাবে আলাদা?


64

আমি গো এর সাথে তুলনামূলকভাবে পরিচিত, এতে বেশ কয়েকটি ছোট প্রোগ্রাম লিখেছি। মরিচা অবশ্যই, আমি এর সাথে কম পরিচিত কিন্তু নজর রাখছি।

সম্প্রতি http://yager.io/programming/go.html পড়ে , আমি ভেবেছিলাম জেনারিক্স যে দুটি উপায় পরিচালিত হয় সেগুলি আমি ব্যক্তিগতভাবে পরীক্ষা করব কারণ নিবন্ধটি অন্যায়ভাবে সমালোচনা করেছে বলে মনে হয়েছিল বাস্তবে, ইন্টারফেসগুলি তেমন কিছু ছিল না। মার্জিতভাবে সম্পাদন করতে পারে না। রাস্টের বৈশিষ্ট্যগুলি কতটা শক্তিশালী ছিল তা সম্পর্কে হাইপ শুনছিলাম এবং গো সম্পর্কে লোকের সমালোচনা ছাড়া কিছুই ছিল না। গোতে কিছু অভিজ্ঞতা থাকার পরে, আমি ভাবলাম যে এটি কতটা সত্য এবং শেষ পর্যন্ত পার্থক্যগুলি কী। আমি যেটি খুঁজে পেয়েছি তা হল বৈশিষ্টগুলি এবং ইন্টারফেসগুলি বেশ একই রকম! শেষ পর্যন্ত, আমি নিশ্চিত যে আমি কিছু মিস করছি কিনা তা নিশ্চিত নই, সুতরাং এখানে তাদের মিলগুলির একটি দ্রুত শিক্ষামূলক গুরত্ব রয়েছে যাতে আপনি আমাকে বলতে পারেন যে আমি কী মিস করেছি!

এখন, আসুন তাদের ডকুমেন্টেশন থেকে গো ইন্টারফেসগুলি একবার দেখুন :

গো-এর ইন্টারফেসগুলি কোনও সামগ্রীর আচরণ নির্দিষ্ট করার জন্য একটি উপায় সরবরাহ করে: যদি কিছু এটি করতে পারে তবে তা এখানে ব্যবহার করা যেতে পারে।

এখন পর্যন্ত সবচেয়ে সাধারণ ইন্টারফেস Stringerযা বস্তুর প্রতিনিধিত্ব করে একটি স্ট্রিং দেয়।

type Stringer interface {
    String() string
}

সুতরাং, যে কোনও বস্তু যা এর উপরে String()সংজ্ঞা দিয়েছে তা একটি Stringerবস্তু object এটি টাইপ স্বাক্ষরগুলিতে ব্যবহার করা যেতে পারে যা func (s Stringer) print()প্রায় সমস্ত বস্তু নেয় এবং তাদের মুদ্রণ করে।

আমাদেরও আছে interface{}যা কোনও বস্তু গ্রহণ করে। তারপরে প্রতিফলনের মাধ্যমে আমাদের রানটাইমের সময়টি নির্ধারণ করতে হবে।


এখন, আসুন তাদের ডকুমেন্টেশন থেকে মরিচা বৈশিষ্ট্য একবার দেখুন :

এর সর্বাধিকতম সময়ে, একটি বৈশিষ্ট্য শূন্য বা আরও বেশি পদ্ধতি স্বাক্ষরের একটি সেট। উদাহরণস্বরূপ, আমরা একক পদ্ধতিতে স্বাক্ষর সহ কনসোলে মুদ্রণযোগ্য জিনিসগুলির জন্য বৈশিষ্ট্য মুদ্রণযোগ্য হিসাবে ঘোষণা করতে পারি:

trait Printable {
    fn print(&self);
}

এটি তাত্ক্ষণিকভাবে আমাদের গো ইন্টারফেসের সাথে বেশ মিল দেখায়। কেবলমাত্র তফাতটি আমি দেখছি যে আমরা কেবল পদ্ধতিগুলি সংজ্ঞায়নের চেয়ে বৈশিষ্ট্যের 'বাস্তবায়ন' সংজ্ঞায়িত করি। সুতরাং, আমরা না

impl Printable for int {
    fn print(&self) { println!("{}", *self) }
}

পরিবর্তে

fn print(a: int) { ... }

বোনাস প্রশ্ন: আপনি যদি কোনও বৈশিষ্ট্য প্রয়োগ করে তবে আপনি ব্যবহার করেন না এমন কোনও ফাংশন সংজ্ঞায়িত করেন তবে জাস্টে কী হবে impl? এটা ঠিক কাজ করে না?

গো-এর ইন্টারফেসগুলির বিপরীতে, মরিচা টাইপ সিস্টেমে টাইপ পরামিতি রয়েছে যা আপনাকে সঠিক জেনারিকস এবং জিনিসগুলি করতে দেয় যেমন interface{}সংকলক এবং রানটাইম আসলে টাইপটি জানতে পারে। উদাহরণ স্বরূপ,

trait Seq<T> {
    fn length(&self) -> uint;
}

যে কোনও প্রকারে কাজ করে এবং সংকলক জানে যে সংকলন সময়ে সিকোয়েন্স উপাদানগুলির প্রকার প্রতিবিম্বটি ব্যবহার না করে।


এখন, আসল প্রশ্ন: আমি কি এখানে কোনও পার্থক্য মিস করছি? সত্যিই তারা যে মত? আমি এখানে মিস করছি এমন কি আরও কিছু মৌলিক পার্থক্য নেই? (ব্যবহারের ক্ষেত্রে। বাস্তবায়নের বিশদগুলি আকর্ষণীয়, তবে শেষ পর্যন্ত যদি সেগুলি একইভাবে কাজ করে তবে তা গুরুত্বপূর্ণ নয়))

সিনথেটিক পার্থক্য ছাড়াও, আমি দেখতে পাই আসল পার্থক্যগুলি:

  1. গো-এর implএকটি বৈশিষ্ট্য প্রয়োগের জন্য বনাম জংয়ের (?) গুলি দরকার হয় automatic
    • মার্জিত বনাম সুস্পষ্ট
  2. মরিচায় টাইপ পরামিতি রয়েছে যা প্রতিবিম্ব ছাড়াই উপযুক্ত জেনারিকের জন্য অনুমতি দেয়।
    • সত্যিই এখানে যান কোনও প্রতিক্রিয়া নেই। এটি হ'ল একমাত্র জিনিস যা উল্লেখযোগ্যভাবে আরও শক্তিশালী এবং শেষ পর্যন্ত এটি বিভিন্ন ধরণের স্বাক্ষর সহ কপি এবং পেস্টের পদ্ধতিগুলির কেবলমাত্র একটি প্রতিস্থাপন।

এগুলি কি কেবলমাত্র তুচ্ছ তাত্পর্যপূর্ণ? যদি তা হয় তবে এটি প্রদর্শিত হবে গো এর ইন্টারফেস / টাইপ সিস্টেমটি বাস্তবে, অনুভূত হিসাবে দুর্বল নয়।

উত্তর:


59

মরচে কী ঘটে যদি আপনি এমন কোনও ক্রিয়া সংজ্ঞায়িত করেন যা কোনও বৈশিষ্ট্য প্রয়োগ করে তবে আপনি ইমপ্ল ব্যবহার করেন না? এটা ঠিক কাজ করে না?

আপনি স্পষ্টভাবে বৈশিষ্ট্য প্রয়োগ করা প্রয়োজন; নাম / স্বাক্ষরের সাথে মিলে যাওয়ার কোনও পদ্ধতি হ'ল মরিচা অর্থহীন।

জেনেরিক কল প্রেরণ

এগুলি কি কেবলমাত্র তুচ্ছ তাত্পর্যপূর্ণ? যদি তা হয় তবে এটি প্রদর্শিত হবে গো এর ইন্টারফেস / টাইপ সিস্টেমটি বাস্তবে, অনুভূত হিসাবে দুর্বল নয়।

স্ট্যাটিক প্রেরণ সরবরাহ না করা নির্দিষ্ট কিছু ক্ষেত্রে (যেমন Iteratorআমি নীচে উল্লেখ করেছি) একটি গুরুত্বপূর্ণ পারফরম্যান্স হিট হতে পারে । আমি মনে করি এটিই আপনার দ্বারা বোঝানো হয়েছে

সত্যিই এখানে যান কোনও প্রতিক্রিয়া নেই। এটি হ'ল একমাত্র জিনিস যা উল্লেখযোগ্যভাবে আরও শক্তিশালী এবং শেষ পর্যন্ত এটি বিভিন্ন ধরণের স্বাক্ষর সহ কপি এবং পেস্টের পদ্ধতিগুলির কেবলমাত্র একটি প্রতিস্থাপন।

তবে আমি এটিকে আরও বিশদে আবরণ করব, কারণ পার্থক্যটি গভীরভাবে বোঝার পক্ষে এটি উপযুক্ত।

মরচে

মরিচের পদ্ধতির সাহায্যে ব্যবহারকারী স্ট্যাটিক প্রেরণ এবং গতিশীল প্রেরণের মধ্যে চয়ন করতে পারে । উদাহরণ হিসাবে, যদি আপনার হয়

trait Foo { fn bar(&self); }

impl Foo for int { fn bar(&self) {} }
impl Foo for String { fn bar(&self) {} }

fn call_bar<T: Foo>(value: T) { value.bar() }

fn main() {
    call_bar(1i);
    call_bar("foo".to_string());
}

তারপরে call_barউপরের দুটি কল যথাক্রমে কলগুলিতে সংকলন করবে,

fn call_bar_int(value: int) { value.bar() }
fn call_bar_string(value: String) { value.bar() }

যেখানে এই .bar()পদ্ধতি কলগুলি স্থির ফাংশন কলগুলি হয়, অর্থাত মেমরির একটি স্থির ফাংশন ঠিকানায়। এটি ইনলাইনের মতো অনুকূলকরণের অনুমতি দেয় কারণ সংকলক ঠিক কোন ফাংশনটি ডাকা হচ্ছে তা জানে । (এটি সি ++ খুব বেশি করে তোলে, কখনও কখনও "মনমোর্ফিজেশন" নামে পরিচিত))

ইন গো

গো কেবলমাত্র "জেনেরিক" ফাংশনগুলির জন্য ডায়নামিক প্রেরণের অনুমতি দেয়, অর্থাত্ পদ্ধতির ঠিকানাটি মান থেকে লোড করা হয় এবং সেখান থেকে কল করা হয়, সুতরাং সঠিক ফাংশনটি কেবল রানটাইমেই জানা যায়। উপরের উদাহরণ ব্যবহার করে

type Foo interface { bar() }

func call_bar(value Foo) { value.bar() }

type X int;
type Y string;
func (X) bar() {}
func (Y) bar() {}

func main() {
    call_bar(X(1))
    call_bar(Y("foo"))
}

এখন, এই দুটি call_barগুলি ইন্টারফেসের vtable থেকে লোড করা call_barঠিকানা সহ সর্বদা উপরের দিকে কল করবে ।bar

নিম্ন স্তরের

উপরেরটি পুনরায় প্রকাশ করতে সি স্বরলিপিতে। মরিচের সংস্করণ তৈরি করে

/* "implementing" the trait */
void bar_int(...) { ... }
void bar_string(...) { ... }

/* the monomorphised `call_bar` function */
void call_bar_int(int value) {
    bar_int(value);
}
void call_bar_string(string value) {
    bar_string(value);
}

int main() {
    call_bar_int(1);
    call_bar_string("foo");
    // pretend that is the (hypothetical) `string` type, not a `char*`
    return 1;
}

গো জন্য, এটি আরও কিছু জাতীয়:

/* implementing the interface */
void bar_int(...) { ... }
void bar_string(...) { ... }

// the Foo interface type
struct Foo {
    void* data;
    struct FooVTable* vtable;
}
struct FooVTable {
    void (*bar)(void*);
}

void call_bar(struct Foo value) {
    value.vtable.bar(value.data);
}

static struct FooVTable int_vtable = { bar_int };
static struct FooVTable string_vtable = { bar_string };

int main() {
    int* i = malloc(sizeof *i);
    *i = 1;
    struct Foo int_data = { i, &int_vtable };
    call_bar(int_data);

    string* s = malloc(sizeof *s);
    *s = "foo"; // again, pretend the types work
    struct Foo string_data = { s, &string_vtable };
    call_bar(string_data);
}

(এটি ঠিক ঠিক নয় --- ভিটিবেলে আরও তথ্য থাকতে হবে --- তবে ডায়নামিক ফাংশন পয়েন্টার হওয়া পদ্ধতি কলটি এখানে প্রাসঙ্গিক।

মরিচা পছন্দ প্রস্তাব

ফিরে যাচ্ছি

মরিচের পদ্ধতির সাহায্যে ব্যবহারকারী স্ট্যাটিক প্রেরণ এবং গতিশীল প্রেরণের মধ্যে চয়ন করতে পারে।

এখনও পর্যন্ত আমি কেবল জাস্টকে স্ট্যাটিকালি প্রেরণ করেছি জেনেরিকগুলি প্রদর্শন করেছি, তবে মরিচা গুণের মতো গতিশীলদের (মূলত একই প্রয়োগের সাথে) বৈশিষ্ট্যযুক্ত বস্তুর মাধ্যমে বেছে নিতে পারে। যেমনটি চিহ্নিত &Foo, এটি কোনও অজানা প্রকারের কাছে ধার করা রেফারেন্স যা Fooবৈশিষ্ট্যটি কার্যকর করে । এই মানগুলির গো / ইন্টারফেস অবজেক্টে একই / খুব অনুরূপ vtable উপস্থাপনা রয়েছে। (একটি বৈশিষ্ট্য অবজেক্টটি "অস্তিত্বের ধরণের" উদাহরণ ))

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

টিএল; ডঃ: জাস্টের রুচির পদ্ধতি প্রোগ্রামারদের বিবেচনার ভিত্তিতে জেনেরিকগুলিতে স্থির এবং গতিশীল প্রেরণ উভয়ই সরবরাহ করে; গো কেবল গতিশীল প্রেরণের অনুমতি দেয়।

প্যারামেট্রিক পলিমারফিজম

তদ্ব্যতীত, বৈশিষ্ট্যগুলিকে জোর দেওয়া এবং প্রতিচ্ছবি প্রতিবিম্বিত করার ফলে মরিচা মজবুতকে আরও শক্তিশালী প্যারাম্যাট্রিক পলিমারফিজম দেয় : প্রোগ্রামার সঠিকভাবে জানে যে কোনও ফাংশন তার যুক্তিগুলির সাথে কী করতে পারে, কারণ এটি জেনেরিক ধরণের বৈশিষ্ট্যগুলি ফাংশনের স্বাক্ষরে প্রয়োগ করা হয়।

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

বিল্ডিং বিমূর্ততা

এটি কিছুটা দুর্দশার বিষয়, সুতরাং আমি কেবল সংক্ষেপে কথা বলব, তবে রাস্টের মতো "যথাযথ" জেনারিক থাকার কারণে গো এর মতো নিম্ন স্তরের ডেটা ধরণের তথ্য পাওয়া যায় mapএবং []প্রকৃতপক্ষে স্ট্যান্ডার্ড লাইব্রেরিতে দৃ types়ভাবে টাইপসেফের মাধ্যমে সরাসরি প্রয়োগ করা যায় এবং মরিচা ( HashMapএবং Vecযথাক্রমে) লিখিত ।

এবং এটি কেবল এই ধরণের নয়, আপনি তাদের উপরে টাইপ-নিরাপদ জেনেরিক কাঠামো তৈরি করতে পারেন, যেমন LruCacheহ্যাশম্যাপের উপরে জেনেরিক ক্যাচিং স্তর। এর মানে হল মানুষ শুধু মান লাইব্রেরি থেকে সরাসরি ডাটা স্ট্রাকচার ব্যবহার করতে পারেন, ছাড়া যেমন ডেটা জমা করতে থাকার interface{}এবং / ঢোকাতে আহরণের টাইপ গবেষকেরা ব্যবহার করুন। এটি হ'ল, যদি আপনার কাছে থাকে তবে আপনি LruCache<int, String>গ্যারান্টিযুক্ত যে কীগুলি সর্বদা হ'ল intএবং মানগুলি সর্বদা Stringসমান: ঘটনাক্রমে ভুল মান সন্নিবেশ করার কোনও উপায় নেই (বা একটি অ- নিষ্কাশনের চেষ্টা করুন String)।


AnyMapমুরগের শক্তিগুলির একটি ভাল প্রদর্শন আমার নিজের , জেনেরিকের সাথে বৈশিষ্ট্যযুক্ত বস্তুগুলির সংমিশ্রণে ভঙ্গুর জিনিসটির একটি সুরক্ষিত এবং অভিব্যক্তিপূর্ণ বিমূর্ততা সরবরাহ করার জন্য যা গো-র প্রয়োজনে লেখা উচিত map[string]interface{}
ক্রিস মরগান

যেমনটি আমি প্রত্যাশা করেছি, মরিচা আরও শক্তিশালী এবং স্থানীয়ভাবে / মার্জিতভাবে আরও পছন্দ দেয় তবে গো এর সিস্টেমটি এতটাই নিকটবর্তী যে বেশিরভাগ জিনিস এটি মিস করে যেমন ছোট হ্যাকগুলি দ্বারা সম্পন্ন করা যায় interface{}। যদিও মরিচা প্রযুক্তিগতভাবে উন্নত বলে মনে হচ্ছে, তবুও আমি মনে করি গো ... এর সমালোচনা কিছুটা কঠোরও হয়েছিল। প্রোগ্রামারটির শক্তি 99% কাজের জন্য সমান।
লোগান

22
@ লোগান, নিম্ন-স্তরের / উচ্চ-কর্মক্ষমতা ডোমেনের জন্য জাস্ট লক্ষ্য করছে (যেমন অপারেটিং সিস্টেম, ওয়েব ব্রাউজারগুলি ... মূল "সিস্টেম" প্রোগ্রামিং স্টাফ), স্থির প্রেরণের বিকল্প নেই (এবং এটি সম্পাদন / অপ্টিমাইজেশন দেয় যা পারফরম্যান্স) এটি অনুমতি দেয়) অগ্রহণযোগ্য। এটি এমন একটি কারণ যা গো Go ধরণের অ্যাপ্লিকেশনগুলির জন্য জাস্ট হিসাবে উপযুক্ত নয়। যাই হোক না কেন, প্রোগ্রামারটির শক্তি সত্যিই সমান নয়, আপনি কোনও পুনরায় ব্যবহারযোগ্য এবং অন্তর্নির্মিত ডেটা স্ট্রাকচারের জন্য রানটাইম টাইপের প্রতিবেদনে ফিরে গিয়ে (টাইপ করার সময়) টাইপ সুরক্ষা হারাবেন।
Huon

10
এটি ঠিক সঠিক - মরিচ আপনাকে আরও অনেক পাওয়ার সরবরাহ করে। আমি মরিচাটিকে নিরাপদ সি ++ হিসাবে মনে করি এবং দ্রুত পাইথন (বা একটি বিস্তৃত সরলীকৃত জাভা) হিসাবে যাই। বিকাশের উত্পাদনশীলতা সবচেয়ে বেশি গুরুত্বপূর্ণ কাজের জন্য (এবং রানটাইম এবং আবর্জনা সংগ্রহের মতো জিনিস সমস্যাযুক্ত নয়) এর জন্য গো (যেমন, ওয়েব সার্ভার, সমকালীন সিস্টেম, কমান্ড লাইন ইউটিলিটিস, ব্যবহারকারীর অ্যাপ্লিকেশন ইত্যাদি) পছন্দ করুন। আপনার যদি প্রতিটি শেষ বিট পারফরম্যান্সের প্রয়োজন হয় (এবং বিকাশকারী উত্পাদনশীলতা লাঞ্ছিত করা হয়) তবে মরিচ (যেমন ব্রাউজারগুলি, অপারেটিং সিস্টেমগুলি, সংস্থান-সীমাবদ্ধ এম্বেডেড সিস্টেমগুলি) চয়ন করুন choose
weberc2
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.