গো-তে এনামগুলিকে উপস্থাপন করার একটি মূ ?় উপায় কী?


522

আমি একটি সরলিকৃত ক্রোমোজোমকে উপস্থাপন করার চেষ্টা করছি, যা এন ঘাঁটিগুলি নিয়ে গঠিত, যার প্রতিটিই কেবল একটি হতে পারে {A, C, T, G}

আমি কোনও এনামের সাথে প্রতিবন্ধকতাগুলি আনুষ্ঠানিক করতে চাই, তবে আমি ভাবছি যে এনামের অনুকরণের সর্বাধিক অভিহিত পদ্ধতিটি গোতে কী।


4
গো স্ট্যান্ডার্ড প্যাকেজগুলিতে এগুলি ধ্রুবক হিসাবে প্রতিনিধিত্ব করা হয়। Golang.org/pkg/os/#pkg-constants
Denys

2
সম্পর্কিত: stackoverflow.com/questions/14236263/...
lbonn


7
@ আইকিজা এই প্রশ্নটি এর আগে 3 বছর আগে জিজ্ঞাসা করা হয়েছিল। সময়ের তীরটি কার্যক্রমে চলছে বলে ধরে নেওয়া এটি এটির একটি সদৃশ হতে পারে না।
কার্বোকেশন

উত্তর:


658

ভাষার চশমা থেকে উদ্ধৃতি: আইওটা

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

const (  // iota is reset to 0
        c0 = iota  // c0 == 0
        c1 = iota  // c1 == 1
        c2 = iota  // c2 == 2
)

const (
        a = 1 << iota  // a == 1 (iota has been reset)
        b = 1 << iota  // b == 2
        c = 1 << iota  // c == 4
)

const (
        u         = iota * 42  // u == 0     (untyped integer constant)
        v float64 = iota * 42  // v == 42.0  (float64 constant)
        w         = iota * 42  // w == 84    (untyped integer constant)
)

const x = iota  // x == 0 (iota has been reset)
const y = iota  // y == 0 (iota has been reset)

এক্সপ্রেশনলিস্টের মধ্যে, প্রতিটি আইওটার মান একই হয় কারণ এটি প্রতিটি কনস্টস্পেকের পরে কেবলমাত্র বৃদ্ধি করা হয়:

const (
        bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0
        bit1, mask1                           // bit1 == 2, mask1 == 1
        _, _                                  // skips iota == 2
        bit3, mask3                           // bit3 == 8, mask3 == 7
)

এই শেষ উদাহরণটি সর্বশেষ খালি খালি অভিব্যক্তি তালিকার অন্তর্নিহিত পুনরাবৃত্তি কাজে লাগায়।


সুতরাং আপনার কোড মত হতে পারে

const (
        A = iota
        C
        T
        G
)

অথবা

type Base int

const (
        A Base = iota
        C
        T
        G
)

আপনি যদি বেসগুলি ইন্টের থেকে পৃথক ধরণের হতে চান।


16
দুর্দান্ত উদাহরণগুলি (আমি সঠিক আইওটা আচরণটি স্মরণ করিনি - যখন এটি বাড়ানো হয় - ফটোগুলি থেকে)। ব্যক্তিগতভাবে আমি একটি এনামকে একটি টাইপ দিতে চাই, সুতরাং এটি যুক্তি, ক্ষেত্র ইত্যাদি হিসাবে ব্যবহৃত হলে এটি টাইপ-চেক করা যায়
এমএনএ

16
খুব আকর্ষণীয় @jnml। তবে আমি একরকম হতাশ যে স্ট্যাটিক টাইপ-চেকিং শিথিল বলে মনে হচ্ছে, উদাহরণস্বরূপ, বেস n ° 42 যা কখনও বিদ্যমান ছিল তা আমাকে ব্যবহার করা থেকে বিরত রাখে
ডেলিপ্লেস

4
গো সংখ্যার সাবঞ্জ্রে টাইপের কোনও ধারণা নেই, যেমন প্যাসকেলের Ord(Base)হ'ল যেমন সীমাবদ্ধ নয় 0..3তবে এর অন্তর্নিহিত সংখ্যার প্রকারের মতোই সীমাবদ্ধতা রয়েছে। এটি একটি ভাষা নকশা পছন্দ, সুরক্ষা এবং কর্মক্ষমতা মধ্যে সমঝোতা। Baseটাইপ করা মানকে স্পর্শ করার সময় প্রতিবার "নিরাপদ" রান টাইম বাউন্ড চেকগুলি বিবেচনা করুন । কেমন এক সংজ্ঞায়িত করা উচিত 'ওভারফ্লো আচরণ Basearithmetics এবং জন্য মান ++এবং --? ইত্যাদি
জেডজেজ

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

10
আপনি iota + 10 থেকে শুরু না করতে ব্যবহার করতে পারেন
মারিয়াল জুয়ান

87

জেএনএমএলের উত্তরের উল্লেখ করে আপনি বেস প্রকারটি একেবারে রফতানি না করে বেস ধরণের নতুন ঘটনাগুলি রোধ করতে পারেন (অর্থাত্ এটি ছোট হাতের অক্ষরে লিখুন)। প্রয়োজনে আপনি একটি রফতানিযোগ্য ইন্টারফেস তৈরি করতে পারেন যা একটি পদ্ধতি রয়েছে যা একটি বেস ধরণের দেয়। এই ইন্টারফেসটি বাইরে থেকে কার্যগুলিতে ব্যবহার করা যেতে পারে যা বেসগুলি সাথে ডিল করে ie

package a

type base int

const (
    A base = iota
    C
    T
    G
)


type Baser interface {
    Base() base
}

// every base must fulfill the Baser interface
func(b base) Base() base {
    return b
}


func(b base) OtherMethod()  {
}

package main

import "a"

// func from the outside that handles a.base via a.Baser
// since a.base is not exported, only exported bases that are created within package a may be used, like a.A, a.C, a.T. and a.G
func HandleBasers(b a.Baser) {
    base := b.Base()
    base.OtherMethod()
}


// func from the outside that returns a.A or a.C, depending of condition
func AorC(condition bool) a.Baser {
    if condition {
       return a.A
    }
    return a.C
}

মূল প্যাকেজটির অভ্যন্তরে a.Baserকার্যকরভাবে এখন একটি এনামের মতো। কেবলমাত্র প্যাকেজের ভিতরেই আপনি নতুন দৃষ্টান্ত সংজ্ঞায়িত করতে পারেন।


10
আপনার পদ্ধতি সে ক্ষেত্রে উপযুক্ত হয় যেখানে baseকেবল পদ্ধতি গ্রহণকারী হিসাবে ব্যবহৃত হয়। যদি আপনার aপ্যাকেজ কোনও প্রকারের পরামিতি গ্রহণ করে কোনও ক্রিয়াকলাপ প্রকাশ করে baseতবে তা বিপজ্জনক হয়ে উঠবে। প্রকৃতপক্ষে, ব্যবহারকারী কেবল এটি আক্ষরিক মান 42 দিয়ে কল করতে পারে, যা ফাংশনটি গ্রহণ করবে baseকারণ এটি কোনও ইন্টিতে কাস্ট করা যায়। এটিকে রোধ করতে, করতে baseএকটি struct: type base struct{value:int}। সমস্যা: আপনি আর ধ্রুবক হিসাবে ঘাঁটি ঘোষণা করতে পারবেন না, কেবলমাত্র মডিউল ভেরিয়েবল। তবে ৪২ টি কখনও baseএই ধরণের একটিতে কাস্ট করা যাবে না ।
নিরিল

6
@ মেটেকিউল আমি আপনার উদাহরণটি বোঝার চেষ্টা করছি তবে পরিবর্তনশীল নামে আপনার পছন্দ এটি অত্যন্ত জটিল করে তুলেছে।
anon58192932

1
উদাহরণগুলির মধ্যে এটি আমার বাগবায়ারগুলির মধ্যে একটি। এফজিএস, আমি বুঝতে পারি এটি লোভনীয়, তবে ভেরিয়েবলটির নামের মতো নয়!
গ্রাহাম নিকোলস

26

আপনি এটি এটি করতে পারেন:

type MessageType int32

const (
    TEXT   MessageType = 0
    BINARY MessageType = 1
)

এই কোড সংকলকটির সাথে এনামের প্রকারটি পরীক্ষা করা উচিত


5
ধ্রুবকগুলি সাধারণত সমস্ত বড় হাতের না করে সাধারণ ক্যামেলকেসে লেখা হয়। প্রাথমিক বড় হাতের অক্ষরের অর্থ হ'ল ভেরিয়েবলটি রফতানি করা হয় যা আপনি যা চান তা হতে পারে বা নাও পারে।
425nesp

1
আমি গো সোর্স কোডটিতে লক্ষ্য করেছি যে এমন একটি মিশ্রণ রয়েছে যেখানে কখনও কখনও ধ্রুবকগুলি সমস্ত বড় হাতের অক্ষর থাকে এবং কখনও কখনও তারা ক্যামিটকেস হয়। আপনার কি কোনও অনুমানের রেফারেন্স আছে?
জেরেমি গাইলার

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

একটি পছন্দ আছে। ভেরিয়েবল, ফাংশন, প্রকার এবং অন্যদের মতো ধ্রুবক নামগুলিও ALLCAPS নয়, মিশ্রক্যাপ বা মিক্সডক্যাপস হওয়া উচিত। উত্স: কোড পর্যালোচনা মন্তব্যসমূহ
রোডল্ফো কারভালহো

22

এটা সত্য যে ব্যবহারের উপরের উদাহরণগুলোতে constএবং iotaযান মধ্যে আদিম enums প্রতিনিধিত্বমূলক অধিকাংশ কথ্য উপায় আছে। তবে আপনি যদি জাভা বা পাইথনের মতো অন্য ভাষায় দেখতে চান সেই জাতীয় আরও পুরোপুরি বৈশিষ্ট্যযুক্ত এনাম তৈরির কোনও উপায় অনুসন্ধান করছেন?

পাইথনের স্ট্রিং এনামের মতো দেখতে এবং অনুভব করা শুরু করার মতো কোনও অবজেক্ট তৈরি করার খুব সহজ উপায় হ'ল:

package main

import (
    "fmt"
)

var Colors = newColorRegistry()

func newColorRegistry() *colorRegistry {
    return &colorRegistry{
        Red:   "red",
        Green: "green",
        Blue:  "blue",
    }
}

type colorRegistry struct {
    Red   string
    Green string
    Blue  string
}

func main() {
    fmt.Println(Colors.Red)
}

মনে করুন আপনিও কিছু ইউটিলিটি পদ্ধতি পছন্দ করতে চাইছিলেন Colors.List(), এবং Colors.Parse("red")। এবং আপনার রঙগুলি আরও জটিল ছিল এবং স্ট্রাক্ট হওয়ার দরকার ছিল। তাহলে আপনি কিছুটা এরকম কিছু করতে পারেন:

package main

import (
    "errors"
    "fmt"
)

var Colors = newColorRegistry()

type Color struct {
    StringRepresentation string
    Hex                  string
}

func (c *Color) String() string {
    return c.StringRepresentation
}

func newColorRegistry() *colorRegistry {

    red := &Color{"red", "F00"}
    green := &Color{"green", "0F0"}
    blue := &Color{"blue", "00F"}

    return &colorRegistry{
        Red:    red,
        Green:  green,
        Blue:   blue,
        colors: []*Color{red, green, blue},
    }
}

type colorRegistry struct {
    Red   *Color
    Green *Color
    Blue  *Color

    colors []*Color
}

func (c *colorRegistry) List() []*Color {
    return c.colors
}

func (c *colorRegistry) Parse(s string) (*Color, error) {
    for _, color := range c.List() {
        if color.String() == s {
            return color, nil
        }
    }
    return nil, errors.New("couldn't find it")
}

func main() {
    fmt.Printf("%s\n", Colors.List())
}

এই মুহুর্তে, নিশ্চিত এটি কার্যকরভাবে কাজ করে তবে আপনি কীভাবে পুনরাবৃত্তিমূলকভাবে রঙ নির্ধারণ করতে হবে তা আপনি পছন্দ করতে পারেন না। যদি আপনি এই মুহুর্তে এটি মুছে ফেলতে চান তবে আপনি নিজের স্ট্রাক্টে ট্যাগ ব্যবহার করতে পারেন এবং এটি সেট আপ করার জন্য কিছু অভিনব প্রতিচ্ছবি করতে পারেন, তবে আশা করি বেশিরভাগ লোককে coverাকতে এটি যথেষ্ট।


19

Go 1.4 হিসাবে, go generateসরঞ্জামটি stringerকমান্ডের সাথে একত্রিত করা হয়েছে যা আপনার এনামটিকে সহজেই ডিবাজেবল এবং মুদ্রণযোগ্য করে তোলে।


আপনি কি জানেন আফসাইট সমাধান। মানে স্ট্রিং -> মাইটাইপ। যেহেতু একটি উপায় সমাধান আদর্শ থেকে অনেক দূরে। এখানে এসবি গিস্ট যা আমি যা চাই তা করি - তবে হাতে লিখে ভুল করা সহজ।
এসআর

11

আমি নিশ্চিত যে এখানে আমাদের অনেক ভাল উত্তর আছে। তবে, আমি কেবল গণনার প্রকারগুলি ব্যবহার করার উপায়টি যুক্ত করার কথা ভেবেছিলাম

package main

import "fmt"

type Enum interface {
    name() string
    ordinal() int
    values() *[]string
}

type GenderType uint

const (
    MALE = iota
    FEMALE
)

var genderTypeStrings = []string{
    "MALE",
    "FEMALE",
}

func (gt GenderType) name() string {
    return genderTypeStrings[gt]
}

func (gt GenderType) ordinal() int {
    return int(gt)
}

func (gt GenderType) values() *[]string {
    return &genderTypeStrings
}

func main() {
    var ds GenderType = MALE
    fmt.Printf("The Gender is %s\n", ds.name())
}

এটি এখন পর্যন্ত এমন একটি মূর্তিযুক্ত উপায় যা আমরা গণিতের ধরন তৈরি করতে পারি এবং গোতে ব্যবহার করতে পারি।

সম্পাদনা:

গণনা করার জন্য ধ্রুবক ব্যবহার করার অন্য একটি উপায় যুক্ত করা হচ্ছে

package main

import (
    "fmt"
)

const (
    // UNSPECIFIED logs nothing
    UNSPECIFIED Level = iota // 0 :
    // TRACE logs everything
    TRACE // 1
    // INFO logs Info, Warnings and Errors
    INFO // 2
    // WARNING logs Warning and Errors
    WARNING // 3
    // ERROR just logs Errors
    ERROR // 4
)

// Level holds the log level.
type Level int

func SetLogLevel(level Level) {
    switch level {
    case TRACE:
        fmt.Println("trace")
        return

    case INFO:
        fmt.Println("info")
        return

    case WARNING:
        fmt.Println("warning")
        return
    case ERROR:
        fmt.Println("error")
        return

    default:
        fmt.Println("default")
        return

    }
}

func main() {

    SetLogLevel(INFO)

}

2
আপনি স্ট্রিং মান সহ ধ্রুবক ঘোষণা করতে পারেন। আইএমও এটি করা সহজ যে আপনি যদি এগুলি প্রদর্শন করতে চান এবং আসলে সংখ্যার মান প্রয়োজন না হয়।
cednarski

4

এখানে একটি উদাহরণ রয়েছে যা কার্যকর হিসাবে প্রমাণিত হবে যখন অনেকগুলি গণনা থাকবে। এটি গোলংয়ের কাঠামো ব্যবহার করে এবং অবজেক্ট অরিয়েন্টেড নীতিগুলির উপর আঁকায় এগুলি সমস্ত একটি একটি সুন্দর সামান্য বান্ডেলে বাঁধা। অন্তর্নিহিত কোডগুলির কোনওটিই পরিবর্তিত হবে না যখন কোনও নতুন গণনা যুক্ত করা বা মোছা হয়। প্রক্রিয়াটি হ'ল:

  • এর জন্য একটি গণনার কাঠামো সংজ্ঞায়িত করুন enumeration items: এনুম আইটেম । এটিতে একটি পূর্ণসংখ্যা এবং স্ট্রিং টাইপ রয়েছে।
  • নির্ধারণ করুন enumerationএকটি তালিকা হিসাবে enumeration items: Enum
  • গণনার জন্য পদ্ধতিগুলি তৈরি করুন। কয়েকটি অন্তর্ভুক্ত করা হয়েছে:
    • enum.Name(index int): প্রদত্ত সূচকের জন্য নামটি দেয়।
    • enum.Index(name string): প্রদত্ত সূচকের জন্য নামটি দেয়।
    • enum.Last(): সূচক এবং শেষের গণনার নাম প্রদান করে
  • আপনার গণনার সংজ্ঞা যুক্ত করুন।

এখানে কিছু কোড রয়েছে:

type EnumItem struct {
    index int
    name  string
}

type Enum struct {
    items []EnumItem
}

func (enum Enum) Name(findIndex int) string {
    for _, item := range enum.items {
        if item.index == findIndex {
            return item.name
        }
    }
    return "ID not found"
}

func (enum Enum) Index(findName string) int {
    for idx, item := range enum.items {
        if findName == item.name {
            return idx
        }
    }
    return -1
}

func (enum Enum) Last() (int, string) {
    n := len(enum.items)
    return n - 1, enum.items[n-1].name
}

var AgentTypes = Enum{[]EnumItem{{0, "StaffMember"}, {1, "Organization"}, {1, "Automated"}}}
var AccountTypes = Enum{[]EnumItem{{0, "Basic"}, {1, "Advanced"}}}
var FlagTypes = Enum{[]EnumItem{{0, "Custom"}, {1, "System"}}}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.