简体   繁体   中英

Panic: interface conversion: * is not inteface X: missing method xxx

I'm working on a project that consume messages from Kafka, unmushal using messagepack or json format, build sql of it and insert them into TDengine database.

The inteface defined as:

type TaosEncoder interface {
    TaosDatabase() string
    TaosSTable() string
    TaosTable() string
    TaosTags() []interface{}
    TaosCols() []string
    TaosValues() []interface{}
}

For an object called Record :

type Record struct {
    DeviceID  string        `json:"deviceID"` // for table name
    Timestamp time.Time     `json:"timestamp"`
    Cols      []interface{} `json:"cols"`
}

Implement the interface:

func (r *Record) TaosCols() []string {
    var tags []string
    return tags
}
// other methods are implemented too

A method will use the interface methods:

func ToTaosBatchInsertSql(l []interface{}) (string, error) {
    records := make([]string, len(l))
    for i, t := range l {
        // type TaosEncoderT = *TaosEncoder
        record, err := ToTaosRecordSql(t.(TaosEncoder))
        if err != nil {
            return "", err
        }
        records[i] = record
    }
    return fmt.Sprintf("insert into %s", strings.Join(records, " ")), nil
}

Use it as this:

records := make([]interface{}, size)
for i := 0; i < size; i++ {
    item := <-q.queue # an channel of Record, defined as: queue chan interface{}
    records[i] = item
}
sqlStr, err := utils.ToTaosBatchInsertSql(records)

It compiles ok, but failed while running like this:

panic: interface conversion: record.Record is not utils.TaosEncoder: missing method TaosCols

goroutine 71 [running]:
xxx/pkg/utils.ToTaosBatchInsertSql(0xc000130c80, 0xc8, 0xc8, 0xc8, 0x0, 0x0, 0x0)

But when I change the implementations of Record - remove *

func (r Record) TaosCols() []string {
    var tags []string
    return tags
}

Then it just works.

I've told to use * in interface implements, so the question is:

  1. Is it ok to implement interface with func (r Record) xxx ?
  2. If not, what can I do?

The cause of this error is related to the method sets of a type.

Assume a type T that has methods with a receiver type of T and some more methods with a receiver type of *T .

Then, if a variable is of type T , it has all methods available that have a pointer receiver of T but none of the methods with receiver type *T .

If a variable is of type *T , it has both sets of methods available, those with receiver type T , and those with receiver type *T .

In your case, type Record has no TaosCols() method, and so it does not implement interface TaosEncoder completely.

If you turn the variable of type Record into a *Record variable, it has all methods available and then would implement the interface.

Method Sets in: Frequently Asked Questions (FAQ) - The Go Programming Language

Method Sets in: The Go Programming Language Specification - The Go Programming Language

A Record is not the same type as a *Record . If you use a pointer receiver for defining the methods that implement the interface, then only *Record implements TaosEncoder .

Based on this:

item := <-q.queue # an channel of Record

it looks like you will need to send a value of *Record on q.queue , rather than a Record .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM