एम्बेडेड गुमनाम इंटरफ़ेस के साथ एक संरचना का मतलब?


89

sort पैकेज:

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

...

type reverse struct {
    Interface
}

Interfaceसंरचना में अनाम इंटरफ़ेस का अर्थ क्या है reverse?


खोजकर्ताओं के लिए, यहां बहुत सरल व्याख्या है: एक क्लोजर एक वास्तुकार के परिप्रेक्ष्य से गोलंग को देखो । लेख का शीर्षक आपको डराने न दें। :)
7stud

10
AIUI, वह लेख ("ए क्लोज़र लुक ...") वास्तव में गुमनाम इंटरफेस को एक संरचना में एम्बेड करने का क्या मतलब है, इस बारे में बात नहीं करता है, यह सिर्फ सामान्य रूप से इंटरफेस के बारे में बात करता है।
एड्रियन लुडविन

जवाबों:


73

इस तरह से रिवर्स इम्प्लीमेंट sort.Interfaceऔर हम अन्य सभी को परिभाषित किए बिना एक विशिष्ट विधि को ओवरराइड कर सकते हैं

type reverse struct {
        // This embedded Interface permits Reverse to use the methods of
        // another Interface implementation.
        Interface
}

ध्यान दें कि यहां कैसे (j,i)इसके बजाय स्वैप होता है (i,j)और यह reverseभी reverseलागू होने के बावजूद संरचना के लिए घोषित एकमात्र तरीका हैsort.Interface

// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
        return r.Interface.Less(j, i)
}

इस पद्धति के अंदर जो भी संरचना होती है, हम उसे एक नई reverseसंरचना में बदल देते हैं ।

// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
        return &reverse{data}
}

वास्तविक मूल्य तब आता है जब आपको लगता है कि यदि यह दृष्टिकोण संभव नहीं था तो आपको क्या करना होगा।

  1. में एक और Reverseविधि जोड़ें sort.Interface?
  2. एक और ReverseInterface बनाएं?
  3. ...?

इस परिवर्तन में से किसी को हज़ारों पैकेजों में कोड की कई और लाइनों की आवश्यकता होगी जो मानक रिवर्स कार्यक्षमता का उपयोग करना चाहते हैं।


3
इसलिए यह आपको इंटरफ़ेस के कुछ तरीकों को फिर से परिभाषित करने की अनुमति देता है?
डेविड David वोंग

2
महत्वपूर्ण हिस्सा यह है कि reverseएक प्रकार का सदस्य है Interface। इस सदस्य के पास इसके तरीके बाहरी संरचना या कॉल करने योग्य हैं।
ब्रायन

इस सुविधा (या दृष्टिकोण) को जावा थ्रू में हम जो करते हैं उसे प्राप्त करने के तरीके के रूप में माना जा सकता है। extendगैर-अमूर्त उप-वर्गों के विस्तार के लिए? मेरे लिए, यह आंतरिक द्वारा कार्यान्वित मौजूदा लोगों का उपयोग करते हुए केवल कुछ विधियों को ओवरराइड करने का एक आसान तरीका हो सकता है Interface
केविन गबोसी

तो यह एक तरह की विरासत है? और return r.Interface.Less(j, i)माता-पिता के कार्यान्वयन को बुला रहा है?
वार्वारिक

पहले से ही दूसरी बार मैं इस बारे में उलझन में हूं। सभी उत्तर इस संरचना के अनजाने उपयोग को भूलने के लिए प्रतीत होते हैं (जिसे वास्तव में कुछ भी छांटने की आवश्यकता है) sort.Sort(sort.Reverse(sort.IntSlice(example))):। मेरे लिए यहाँ दर्द बिंदु: विधि क्रमबद्ध रिवर्स संरचना को बढ़ावा मिलता है, लेकिन कॉल गैर-सदस्य (रिसीवर) शैली है।
18 अप्रैल को सीबी

41

ठीक है, स्वीकृत उत्तर ने मुझे समझने में मदद की, लेकिन मैंने एक स्पष्टीकरण पोस्ट करने का फैसला किया, जो मुझे लगता है कि मेरे सोचने के तरीके से बेहतर है।

"प्रभावी गो" एम्बेडेड अन्य इंटरफेस होने इंटरफेस के उदाहरण हैं:

// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
    Reader
    Writer
}

और एक संरचना जिसमें अन्य संरचनाएं शामिल हैं:

// ReadWriter stores pointers to a Reader and a Writer.
// It implements io.ReadWriter.
type ReadWriter struct {
    *Reader  // *bufio.Reader
    *Writer  // *bufio.Writer
}

लेकिन एक इंटरफ़ेस के अंतःस्थापित होने वाली संरचना का कोई उल्लेख नहीं है। sortपैकेज में यह देखकर मैं उलझन में था :

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

...

type reverse struct {
    Interface
}

लेकिन विचार सरल है। यह लगभग समान है:

type reverse struct {
    IntSlice  // IntSlice struct attaches the methods of Interface to []int, sorting in increasing order
}

के IntSliceप्रचार के तरीके reverse

और इस:

type reverse struct {
    Interface
}

इसका मतलब है कि sort.reverseइंटरफ़ेस को लागू करने वाले किसी भी संरचना को एम्बेड कर सकते हैं sort.Interfaceऔर इंटरफ़ेस के पास जो भी तरीके हैं, उन्हें बढ़ावा दिया जाएगा reverse

sort.InterfaceLess(i, j int) boolअब अधिरोहित किया जा सकता है जो विधि है:

// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

समझने में मेरी उलझन

type reverse struct {
    Interface
}

क्या मैंने सोचा था कि एक संरचना में निश्चित संरचना होती है, अर्थात निश्चित प्रकार के क्षेत्रों की निश्चित संख्या।

लेकिन निम्नलिखित मुझे गलत साबित करता है:

package main

import "fmt"

// some interface
type Stringer interface {
    String() string
}

// a struct that implements Stringer interface
type Struct1 struct {
    field1 string
}

func (s Struct1) String() string {
    return s.field1
}


// another struct that implements Stringer interface, but has a different set of fields
type Struct2 struct {
    field1 []string
    dummy bool
}

func (s Struct2) String() string {
    return fmt.Sprintf("%v, %v", s.field1, s.dummy)
}


// container that can embedd any struct which implements Stringer interface
type StringerContainer struct {
    Stringer
}


func main() {
    // the following prints: This is Struct1
    fmt.Println(StringerContainer{Struct1{"This is Struct1"}})
    // the following prints: [This is Struct1], true
    fmt.Println(StringerContainer{Struct2{[]string{"This", "is", "Struct1"}, true}})
    // the following does not compile:
    // cannot use "This is a type that does not implement Stringer" (type string)
    // as type Stringer in field value:
    // string does not implement Stringer (missing String method)
    fmt.Println(StringerContainer{"This is a type that does not implement Stringer"})
}

3
यदि मेरी समझ सही है, तो इंटरफ़ेस मान एई पॉइंटर द्वारा उसे दिए गए इंस्टेंस को दर्शाते हैं और इंस्ट्रक्टर टाइप के तरीके के लिए एक पॉइंटर। इसलिए सभी इंटरफ़ेस मानों की मेमोरी में समान संरचना होती है। संरचनात्मक रूप से, एम्बेडिंग रचना के समान है। यहां तक ​​कि एक इंटरफ़ेस को एम्बेड करने वाली एक संरचना में एक निश्चित संरचना होगी। उदाहरणों की संरचना इंटरफ़ेस बिंदुओं के लिए भिन्न होगी।
निशांत जॉर्ज अग्रवाल

मुझे यह स्वीकार किए जाने वाले से बेहतर उत्तर मिला क्योंकि इसने और अधिक विस्तार, एक स्पष्ट उदाहरण और प्रलेखन के लिए एक लिंक दिया।
110100100

28

बयान

type reverse struct {
    Interface
}

आपको reverseइंटरफ़ेस को लागू करने वाली हर चीज के साथ आरंभ करने में सक्षम बनाता है Interface। उदाहरण:

&reverse{sort.Intslice([]int{1,2,3})}

इस प्रकार, एम्बेडेड Interfaceमान द्वारा कार्यान्वित सभी विधियाँ बाहर की ओर पॉपुलेट हो जाती हैं, जबकि आप अभी भी उनमें से कुछ को ओवरराइड करने में सक्षम हैं reverse, उदाहरण के Lessलिए छँटाई को उलटने के लिए।

यह वास्तव में होता है जब आप उपयोग करते हैं sort.Reverse। आप कल्पना के संरचनात्मक अनुभाग में एम्बेड करने के बारे में पढ़ सकते हैं ।


पहले से ही दूसरी बार मैं इस बारे में उलझन में हूं। सभी उत्तर इस संरचना के अनजाने उपयोग को भूलने के लिए प्रतीत होते हैं (जिसे वास्तव में कुछ भी छांटने की आवश्यकता है) sort.Sort(sort.Reverse(sort.IntSlice(example))):। मेरे लिए यहाँ दर्द बिंदु: विधि क्रमबद्ध रिवर्स संरचना को बढ़ावा मिलता है, लेकिन कॉल गैर-सदस्य (रिसीवर) शैली है।
देखिए

@seebi यदि यह एक ऐसा प्रश्न है जो मुझे नहीं मिलता है, तो क्षमा करें। इसके अलावा, Sortविधि का प्रचार नहीं किया जाता है, यह कुछ ऐसा लेता है जो संतुष्ट करता है sort.Interfaceऔर रिवर्स एक ऐसी चीज है, यह सिर्फ अपने एम्बेडेड sort.Interfaceडेटा के प्रासंगिक तरीकों को बदलता है ताकि परिणामी प्रकार उलट हो।
नीमो

सवाल नहीं, सिर्फ एक टिप्पणी, आप सही हैं मेरा मतलब है कम, स्वैप, लेन विधियां!
देखिए

7

मैं अपना स्पष्टीकरण भी दूंगा। sortपैकेज एक unexported प्रकार परिभाषित करता reverseहै, जो एक struct, कि एम्बेड है Interface

type reverse struct {
    // This embedded Interface permits Reverse to use the methods of
    // another Interface implementation.
    Interface
}

यह दूसरे इंटरफ़ेस कार्यान्वयन के तरीकों का उपयोग करने के लिए रिवर्स की अनुमति देता है। यह तथाकथित है composition, जो कि गो की एक शक्तिशाली विशेषता है।

एंबेडेड वैल्यू की Lessविधि को reverseकॉल करने की Lessविधि है Interface, लेकिन सूचकांकों के साथ, फ़्लिप परिणाम के क्रम को उलटते हुए।

// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

Lenऔर Swapअन्य दो विधियां reverse, मूल रूप से मूल रूप से प्रदान की जाती हैं Interfaceक्योंकि यह एक एम्बेडेड क्षेत्र है। निर्यात किया गया Reverseफ़ंक्शन उस reverseप्रकार का एक उदाहरण देता है जिसमें मूल Interfaceमान होता है।

// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
    return &reverse{data}
}

मेरे लिए यह विरासत की तरह दिखता है। " एम्बेडेड वैल्यू की Lessविधि को reverseकॉल करने की Lessविधि Interface, लेकिन सूचकांकों के फ़्लिप होने के साथ, क्रमबद्ध परिणामों के क्रम को उलट देते हैं।" - यह माता-पिता के कार्यान्वयन को कॉल करने जैसा लगता है।
वार्वारिक

जब तक टाइप रिवर्स के पास केवल एक फ़ील्ड होता है, जो इंटरफ़ेस इंटरफ़ेस को लागू करता है, यह इंटरफ़ेस इंटरफ़ेस का सदस्य भी बन जाता है: 0
एलन ग्वावाटुडे

1

परीक्षणों में मॉक लिखते समय मुझे यह सुविधा बहुत मददगार लगती है ।

यहाँ इस तरह के एक उदाहरण है:

package main_test

import (
    "fmt"
    "testing"
)

// Item represents the entity retrieved from the store
// It's not relevant in this example
type Item struct {
    First, Last string
}

// Store abstracts the DB store
type Store interface {
    Create(string, string) (*Item, error)
    GetByID(string) (*Item, error)
    Update(*Item) error
    HealthCheck() error
    Close() error
}

// this is a mock implementing Store interface
type storeMock struct {
    Store
    // healthy is false by default
    healthy bool
}

// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
    if !s.healthy {
        return fmt.Errorf("mock error")
    }
    return nil
}

// IsHealthy is the tested function
func IsHealthy(s Store) bool {
    return s.HealthCheck() == nil
}

func TestIsHealthy(t *testing.T) {
    mock := &storeMock{}
    if IsHealthy(mock) {
        t.Errorf("IsHealthy should return false")
    }

    mock = &storeMock{healthy: true}
    if !IsHealthy(mock) {
        t.Errorf("IsHealthy should return true")
    }
}

का उपयोग करके:

type storeMock struct {
    Store
    ...
}

सभी Storeतरीकों का मजाक उड़ाने की जरूरत नहीं है । केवल HealthCheckमजाक किया जा सकता है, क्योंकि TestIsHealthyपरीक्षण में केवल इस पद्धति का उपयोग किया जाता है ।

testआदेश के परिणाम के नीचे :

$ go test -run '^TestIsHealthy$' ./main_test.go           
ok      command-line-arguments  0.003s

एक वास्तविक दुनिया उदाहरण उपयोग के इस मामले से एक के परीक्षण जब पा सकते हैं एडब्ल्यूएस एसडीके


इसे और अधिक स्पष्ट करने के लिए, यहाँ बदसूरत विकल्प है - Storeइंटरफ़ेस को संतुष्ट करने के लिए न्यूनतम एक को लागू करने की आवश्यकता है :

type storeMock struct {
    healthy bool
}

func (s *storeMock) Create(a, b string) (i *Item, err error) {
    return
}
func (s *storeMock) GetByID(a string) (i *Item, err error) {
    return
}
func (s *storeMock) Update(i *Item) (err error) {
    return
}

// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
    if !s.healthy {
        return fmt.Errorf("mock error")
    }
    return nil
}

func (s *storeMock) Close() (err error) {
    return
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.