【go语言之thrift协议一】

news2024/10/7 20:34:45

go语言之thrift协议

  • thrift文件
    • shared.thrift
      • SharedStruct
      • SharedService
      • SharedServiceProcessor
      • SharedServiceGetStructArgs
      • SharedServiceGetStructResult
    • tutorial.thrift
      • 基本数据类型
      • 引入其他thrift文件
      • 自定义类型
      • 定义常量
      • enum
      • 继承

thrift 相对于grpc而言,可能用的不是特别多,但是也是有一定的知名度,废话不多说,直接看一下实现。
首先就是安装,对于mac系统来说,直接就是

brew install thrift

当输入thrift --version 显示版本说明安装成功.
在这里插入图片描述
这里的示例代码是基于官方的示例去做的,地址是 官方示例。

这一篇文件主要介绍的是thrift的文件,以后生成对应的go的代码

thrift文件

然后和protobuf,先写proto文件,然后生成不同语言的文件一样,thrift是以thrift的文件作为后缀,然后使用thrift命令来去生成不同语言的文件。
这里看一下官方的示例

shared.thrift

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/**
 * This Thrift file can be included by other Thrift files that want to share
 * these definitions.
 */

namespace cl shared
namespace cpp shared
namespace d share // "shared" would collide with the eponymous D keyword.
namespace dart shared
namespace java shared
namespace perl shared
namespace php shared
namespace haxe shared
namespace netstd shared


struct SharedStruct {
  1: i32 key
  2: string value
}

service SharedService {
  SharedStruct getStruct(1: i32 key)
}

首先这里定义了一个shared.thrift的文件,然后这里是定义了namespace,然后是SharedStruct这个结构体,这个里面定义了两个成员,第一个是key,属性是int32。然后就是value,属性是string。
然后就是SharedService。这个就是需要实现的方法,在golang中就是interface,在java中就是abstract。
接下来看一下生成的go文件

SharedStruct

type SharedStruct struct {
	Key   int32  `thrift:"key,1" db:"key" json:"key"`
	Value string `thrift:"value,2" db:"value" json:"value"`
}

func NewSharedStruct() *SharedStruct {
	return &SharedStruct{}
}

func (p *SharedStruct) GetKey() int32 {
	return p.Key
}

func (p *SharedStruct) GetValue() string {
	return p.Value
}
func (p *SharedStruct) Read(ctx context.Context, iprot thrift.TProtocol) error {
	if _, err := iprot.ReadStructBegin(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
	}

	for {
		_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)
		if err != nil {
			return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
		}
		if fieldTypeId == thrift.STOP {
			break
		}
		switch fieldId {
		case 1:
			if fieldTypeId == thrift.I32 {
				if err := p.ReadField1(ctx, iprot); err != nil {
					return err
				}
			} else {
				if err := iprot.Skip(ctx, fieldTypeId); err != nil {
					return err
				}
			}
		case 2:
			if fieldTypeId == thrift.STRING {
				if err := p.ReadField2(ctx, iprot); err != nil {
					return err
				}
			} else {
				if err := iprot.Skip(ctx, fieldTypeId); err != nil {
					return err
				}
			}
		default:
			if err := iprot.Skip(ctx, fieldTypeId); err != nil {
				return err
			}
		}
		if err := iprot.ReadFieldEnd(ctx); err != nil {
			return err
		}
	}
	if err := iprot.ReadStructEnd(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
	}
	return nil
}

func (p *SharedStruct) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {
	if v, err := iprot.ReadI32(ctx); err != nil {
		return thrift.PrependError("error reading field 1: ", err)
	} else {
		p.Key = v
	}
	return nil
}

func (p *SharedStruct) ReadField2(ctx context.Context, iprot thrift.TProtocol) error {
	if v, err := iprot.ReadString(ctx); err != nil {
		return thrift.PrependError("error reading field 2: ", err)
	} else {
		p.Value = v
	}
	return nil
}

func (p *SharedStruct) Write(ctx context.Context, oprot thrift.TProtocol) error {
	if err := oprot.WriteStructBegin(ctx, "SharedStruct"); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
	}
	if p != nil {
		if err := p.writeField1(ctx, oprot); err != nil {
			return err
		}
		if err := p.writeField2(ctx, oprot); err != nil {
			return err
		}
	}
	if err := oprot.WriteFieldStop(ctx); err != nil {
		return thrift.PrependError("write field stop error: ", err)
	}
	if err := oprot.WriteStructEnd(ctx); err != nil {
		return thrift.PrependError("write struct stop error: ", err)
	}
	return nil
}

func (p *SharedStruct) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {
	if err := oprot.WriteFieldBegin(ctx, "key", thrift.I32, 1); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:key: ", p), err)
	}
	if err := oprot.WriteI32(ctx, int32(p.Key)); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T.key (1) field write error: ", p), err)
	}
	if err := oprot.WriteFieldEnd(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write field end error 1:key: ", p), err)
	}
	return err
}

func (p *SharedStruct) writeField2(ctx context.Context, oprot thrift.TProtocol) (err error) {
	if err := oprot.WriteFieldBegin(ctx, "value", thrift.STRING, 2); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:value: ", p), err)
	}
	if err := oprot.WriteString(ctx, string(p.Value)); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T.value (2) field write error: ", p), err)
	}
	if err := oprot.WriteFieldEnd(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write field end error 2:value: ", p), err)
	}
	return err
}

func (p *SharedStruct) Equals(other *SharedStruct) bool {
	if p == other {
		return true
	} else if p == nil || other == nil {
		return false
	}
	if p.Key != other.Key {
		return false
	}
	if p.Value != other.Value {
		return false
	}
	return true
}

func (p *SharedStruct) String() string {
	if p == nil {
		return "<nil>"
	}
	return fmt.Sprintf("SharedStruct(%+v)", *p)
}

可以看出来这里除了生成通常的GetKey 和 GetValue方法,还生成了Read 还有 ReadFile等方法,当然因为用到的时候再说。

SharedService

这个方法生成了好几个方法。里面有一个getStruct方法,参数是int返回了SharedStruct 的结构体。

type SharedService interface {
	// Parameters:
	//  - Key
	GetStruct(ctx context.Context, key int32) (_r *SharedStruct, _err error)
}

type SharedServiceClient struct {
	c    thrift.TClient
	meta thrift.ResponseMeta
}

func NewSharedServiceClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *SharedServiceClient {
	return &SharedServiceClient{
		c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)),
	}
}

func NewSharedServiceClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *SharedServiceClient {
	return &SharedServiceClient{
		c: thrift.NewTStandardClient(iprot, oprot),
	}
}

func NewSharedServiceClient(c thrift.TClient) *SharedServiceClient {
	return &SharedServiceClient{
		c: c,
	}
}

func (p *SharedServiceClient) Client_() thrift.TClient {
	return p.c
}

func (p *SharedServiceClient) LastResponseMeta_() thrift.ResponseMeta {
	return p.meta
}

func (p *SharedServiceClient) SetLastResponseMeta_(meta thrift.ResponseMeta) {
	p.meta = meta
}

// Parameters:
//   - Key
func (p *SharedServiceClient) GetStruct(ctx context.Context, key int32) (_r *SharedStruct, _err error) {
	var _args0 SharedServiceGetStructArgs
	_args0.Key = key
	var _result2 SharedServiceGetStructResult
	var _meta1 thrift.ResponseMeta
	_meta1, _err = p.Client_().Call(ctx, "getStruct", &_args0, &_result2)
	p.SetLastResponseMeta_(_meta1)
	if _err != nil {
		return
	}
	return _result2.GetSuccess(), nil
}

然后看一下 这里首先是生成了一个SharedService的interface,然后定义了一个GetStruct 方法,这个是符合预期。然后看一下实现。
这里是SharedServiceClient实现了这个interface。然后就是如何获取,这里是有三个方法。

  1. NewSharedServiceClientFactory
  2. NewSharedServiceClientProtocol
  3. NewSharedServiceClient
    前两个方法都调用了NewTStandardClient这个方法去生成thrift.TClient。这个thrift.TClient是一个interface是
// ResponseMeta represents the metadata attached to the response.
type ResponseMeta struct {
	// The headers in the response, if any.
	// If the underlying transport/protocol is not THeader, this will always be nil.
	Headers THeaderMap
}

type TClient interface {
	Call(ctx context.Context, method string, args, result TStruct) (ResponseMeta, error)
}

// TStandardClient implements TClient, and uses the standard message format for Thrift.
// It is not safe for concurrent use.
func NewTStandardClient(inputProtocol, outputProtocol TProtocol) *TStandardClient {
	return &TStandardClient{
		iprot: inputProtocol,
		oprot: outputProtocol,
	}
}

可以看出来这个NewTStandardClient的接收参数是 TProtocol 这个interface。然后只不过第一个NewSharedServiceClientFactory是通过thrift.TProtocolFactory去获取的。然后NewSharedServiceClientProtocol是直接传进去的,然后NewSharedServiceClient是直接通过thrift.TClient 去调用的。

SharedServiceProcessor

然后这里还生成了SharedServiceProcessor 这样的的一个结构体,然后看一下这个结构体以及生成的方法。

type SharedServiceProcessor struct {
	processorMap map[string]thrift.TProcessorFunction
	handler      SharedService
}

func (p *SharedServiceProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {
	p.processorMap[key] = processor
}

func (p *SharedServiceProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {
	processor, ok = p.processorMap[key]
	return processor, ok
}

func (p *SharedServiceProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {
	return p.processorMap
}

func NewSharedServiceProcessor(handler SharedService) *SharedServiceProcessor {
	self3 := &SharedServiceProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)}
	self3.processorMap["getStruct"] = &sharedServiceProcessorGetStruct{handler: handler}
	return self3
}

func (p *SharedServiceProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
	name, _, seqId, err2 := iprot.ReadMessageBegin(ctx)
	if err2 != nil {
		return false, thrift.WrapTException(err2)
	}
	if processor, ok := p.GetProcessorFunction(name); ok {
		return processor.Process(ctx, seqId, iprot, oprot)
	}
	iprot.Skip(ctx, thrift.STRUCT)
	iprot.ReadMessageEnd(ctx)
	x4 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name)
	oprot.WriteMessageBegin(ctx, name, thrift.EXCEPTION, seqId)
	x4.Write(ctx, oprot)
	oprot.WriteMessageEnd(ctx)
	oprot.Flush(ctx)
	return false, x4

}

type sharedServiceProcessorGetStruct struct {
	handler SharedService
}

func (p *sharedServiceProcessorGetStruct) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
	args := SharedServiceGetStructArgs{}
	var err2 error
	if err2 = args.Read(ctx, iprot); err2 != nil {
		iprot.ReadMessageEnd(ctx)
		x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())
		oprot.WriteMessageBegin(ctx, "getStruct", thrift.EXCEPTION, seqId)
		x.Write(ctx, oprot)
		oprot.WriteMessageEnd(ctx)
		oprot.Flush(ctx)
		return false, thrift.WrapTException(err2)
	}
	iprot.ReadMessageEnd(ctx)

	tickerCancel := func() {}
	// Start a goroutine to do server side connectivity check.
	if thrift.ServerConnectivityCheckInterval > 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithCancel(ctx)
		defer cancel()
		var tickerCtx context.Context
		tickerCtx, tickerCancel = context.WithCancel(context.Background())
		defer tickerCancel()
		go func(ctx context.Context, cancel context.CancelFunc) {
			ticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)
			defer ticker.Stop()
			for {
				select {
				case <-ctx.Done():
					return
				case <-ticker.C:
					if !iprot.Transport().IsOpen() {
						cancel()
						return
					}
				}
			}
		}(tickerCtx, cancel)
	}

	result := SharedServiceGetStructResult{}
	var retval *SharedStruct
	if retval, err2 = p.handler.GetStruct(ctx, args.Key); err2 != nil {
		tickerCancel()
		if err2 == thrift.ErrAbandonRequest {
			return false, thrift.WrapTException(err2)
		}
		x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing getStruct: "+err2.Error())
		oprot.WriteMessageBegin(ctx, "getStruct", thrift.EXCEPTION, seqId)
		x.Write(ctx, oprot)
		oprot.WriteMessageEnd(ctx)
		oprot.Flush(ctx)
		return true, thrift.WrapTException(err2)
	} else {
		result.Success = retval
	}
	tickerCancel()
	if err2 = oprot.WriteMessageBegin(ctx, "getStruct", thrift.REPLY, seqId); err2 != nil {
		err = thrift.WrapTException(err2)
	}
	if err2 = result.Write(ctx, oprot); err == nil && err2 != nil {
		err = thrift.WrapTException(err2)
	}
	if err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {
		err = thrift.WrapTException(err2)
	}
	if err2 = oprot.Flush(ctx); err == nil && err2 != nil {
		err = thrift.WrapTException(err2)
	}
	if err != nil {
		return
	}
	return true, err
}

这里生成了一个process的方法,然后核心结构体是SharedServiceProcessor 从结构体成员可以看出来主要成员是 processorMap 然后属性是 map[string]thrift.TProcessorFunction。
然后NewSharedServiceProcessor的时候可以是看出来key的名称getStruct,value是sharedServiceProcessorGetStruct然后实现了Processde 的方法。至于用处后面在使用的时候再具体说一下。

SharedServiceGetStructArgs

这个SharedServiceGetStructArgs还得是说到SharedService的成员GetStruct方法,这个方法里面有一个参数key,类型是int32.这里为了这个key还专门生成了一个结构体.然后看一下成员

type SharedServiceGetStructArgs struct {
	Key int32 `thrift:"key,1" db:"key" json:"key"`
}

func NewSharedServiceGetStructArgs() *SharedServiceGetStructArgs {
	return &SharedServiceGetStructArgs{}
}

func (p *SharedServiceGetStructArgs) GetKey() int32 {
	return p.Key
}
func (p *SharedServiceGetStructArgs) Read(ctx context.Context, iprot thrift.TProtocol) error {
	if _, err := iprot.ReadStructBegin(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
	}

	for {
		_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)
		if err != nil {
			return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
		}
		if fieldTypeId == thrift.STOP {
			break
		}
		switch fieldId {
		case 1:
			if fieldTypeId == thrift.I32 {
				if err := p.ReadField1(ctx, iprot); err != nil {
					return err
				}
			} else {
				if err := iprot.Skip(ctx, fieldTypeId); err != nil {
					return err
				}
			}
		default:
			if err := iprot.Skip(ctx, fieldTypeId); err != nil {
				return err
			}
		}
		if err := iprot.ReadFieldEnd(ctx); err != nil {
			return err
		}
	}
	if err := iprot.ReadStructEnd(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
	}
	return nil
}

func (p *SharedServiceGetStructArgs) ReadField1(ctx context.Context, iprot thrift.TProtocol) error {
	if v, err := iprot.ReadI32(ctx); err != nil {
		return thrift.PrependError("error reading field 1: ", err)
	} else {
		p.Key = v
	}
	return nil
}

func (p *SharedServiceGetStructArgs) Write(ctx context.Context, oprot thrift.TProtocol) error {
	if err := oprot.WriteStructBegin(ctx, "getStruct_args"); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
	}
	if p != nil {
		if err := p.writeField1(ctx, oprot); err != nil {
			return err
		}
	}
	if err := oprot.WriteFieldStop(ctx); err != nil {
		return thrift.PrependError("write field stop error: ", err)
	}
	if err := oprot.WriteStructEnd(ctx); err != nil {
		return thrift.PrependError("write struct stop error: ", err)
	}
	return nil
}

func (p *SharedServiceGetStructArgs) writeField1(ctx context.Context, oprot thrift.TProtocol) (err error) {
	if err := oprot.WriteFieldBegin(ctx, "key", thrift.I32, 1); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:key: ", p), err)
	}
	if err := oprot.WriteI32(ctx, int32(p.Key)); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T.key (1) field write error: ", p), err)
	}
	if err := oprot.WriteFieldEnd(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write field end error 1:key: ", p), err)
	}
	return err
}

func (p *SharedServiceGetStructArgs) String() string {
	if p == nil {
		return "<nil>"
	}
	return fmt.Sprintf("SharedServiceGetStructArgs(%+v)", *p)
}

这个看起来很多,然后很多无用的方法其实是不用去看的。

SharedServiceGetStructResult

这个其实是和上面的SharedServiceGetStructArgs类型,只不是上面的是SharedService里面成员GetStruct方法的成员,然后这个SharedServiceGetStructResult是GetStruct的结果的封装,所以成员success的属性是SharedStruct。然后看一下官方的实现

type SharedServiceGetStructResult struct {
	Success *SharedStruct `thrift:"success,0" db:"success" json:"success,omitempty"`
}

func NewSharedServiceGetStructResult() *SharedServiceGetStructResult {
	return &SharedServiceGetStructResult{}
}

var SharedServiceGetStructResult_Success_DEFAULT *SharedStruct

func (p *SharedServiceGetStructResult) GetSuccess() *SharedStruct {
	if !p.IsSetSuccess() {
		return SharedServiceGetStructResult_Success_DEFAULT
	}
	return p.Success
}
func (p *SharedServiceGetStructResult) IsSetSuccess() bool {
	return p.Success != nil
}

func (p *SharedServiceGetStructResult) Read(ctx context.Context, iprot thrift.TProtocol) error {
	if _, err := iprot.ReadStructBegin(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
	}

	for {
		_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)
		if err != nil {
			return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
		}
		if fieldTypeId == thrift.STOP {
			break
		}
		switch fieldId {
		case 0:
			if fieldTypeId == thrift.STRUCT {
				if err := p.ReadField0(ctx, iprot); err != nil {
					return err
				}
			} else {
				if err := iprot.Skip(ctx, fieldTypeId); err != nil {
					return err
				}
			}
		default:
			if err := iprot.Skip(ctx, fieldTypeId); err != nil {
				return err
			}
		}
		if err := iprot.ReadFieldEnd(ctx); err != nil {
			return err
		}
	}
	if err := iprot.ReadStructEnd(ctx); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
	}
	return nil
}

func (p *SharedServiceGetStructResult) ReadField0(ctx context.Context, iprot thrift.TProtocol) error {
	p.Success = &SharedStruct{}
	if err := p.Success.Read(ctx, iprot); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err)
	}
	return nil
}

func (p *SharedServiceGetStructResult) Write(ctx context.Context, oprot thrift.TProtocol) error {
	if err := oprot.WriteStructBegin(ctx, "getStruct_result"); err != nil {
		return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
	}
	if p != nil {
		if err := p.writeField0(ctx, oprot); err != nil {
			return err
		}
	}
	if err := oprot.WriteFieldStop(ctx); err != nil {
		return thrift.PrependError("write field stop error: ", err)
	}
	if err := oprot.WriteStructEnd(ctx); err != nil {
		return thrift.PrependError("write struct stop error: ", err)
	}
	return nil
}

func (p *SharedServiceGetStructResult) writeField0(ctx context.Context, oprot thrift.TProtocol) (err error) {
	if p.IsSetSuccess() {
		if err := oprot.WriteFieldBegin(ctx, "success", thrift.STRUCT, 0); err != nil {
			return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err)
		}
		if err := p.Success.Write(ctx, oprot); err != nil {
			return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err)
		}
		if err := oprot.WriteFieldEnd(ctx); err != nil {
			return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err)
		}
	}
	return err
}

func (p *SharedServiceGetStructResult) String() string {
	if p == nil {
		return "<nil>"
	}
	return fmt.Sprintf("SharedServiceGetStructResult(%+v)", *p)
}

tutorial.thrift

这个文件里面其实说的挺多的,主要是对thrift协议的介绍,看起来要不grpc的协议语法更多一些。

基本数据类型

 *  bool        Boolean, one byte
 *  i8 (byte)   Signed 8-bit integer
 *  i16         Signed 16-bit integer
 *  i32         Signed 32-bit integer
 *  i64         Signed 64-bit integer
 *  double      64-bit floating point value
 *  string      String
 *  binary      Blob (byte array)
 *  map<t1,t2>  Map from one type to another
 *  list<t1>    Ordered list of one type
 *  set<t1>     Set of unique elements of one type

引入其他thrift文件

以上面介绍的shared.thrift为例,这里就是

include "shared.thrift"

自定义类型

thrift的实现是

typedef i32 MyInteger

然后生成的是

type MyInteger int32

func MyIntegerPtr(v MyInteger) *MyInteger { return &v }

定义常量

thrift的实现是

const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

这个很奇怪在go中没有找到

enum

thrift的实现是

 */
enum Operation {
  ADD = 1,
  SUBTRACT = 2,
  MULTIPLY = 3,
  DIVIDE = 4
}

go的实现是

type Operation int64

const (
	Operation_ADD      Operation = 1
	Operation_SUBTRACT Operation = 2
	Operation_MULTIPLY Operation = 3
	Operation_DIVIDE   Operation = 4
)

func (p Operation) String() string {
	switch p {
	case Operation_ADD:
		return "ADD"
	case Operation_SUBTRACT:
		return "SUBTRACT"
	case Operation_MULTIPLY:
		return "MULTIPLY"
	case Operation_DIVIDE:
		return "DIVIDE"
	}
	return "<UNSET>"
}

func OperationFromString(s string) (Operation, error) {
	switch s {
	case "ADD":
		return Operation_ADD, nil
	case "SUBTRACT":
		return Operation_SUBTRACT, nil
	case "MULTIPLY":
		return Operation_MULTIPLY, nil
	case "DIVIDE":
		return Operation_DIVIDE, nil
	}
	return Operation(0), fmt.Errorf("not a valid Operation string")
}

func OperationPtr(v Operation) *Operation { return &v }

func (p Operation) MarshalText() ([]byte, error) {
	return []byte(p.String()), nil
}

func (p *Operation) UnmarshalText(text []byte) error {
	q, err := OperationFromString(string(text))
	if err != nil {
		return err
	}
	*p = q
	return nil
}

func (p *Operation) Scan(value interface{}) error {
	v, ok := value.(int64)
	if !ok {
		return errors.New("Scan value is not int64")
	}
	*p = Operation(v)
	return nil
}

func (p *Operation) Value() (driver.Value, error) {
	if p == nil {
		return nil, nil
	}
	return int64(*p), nil
}

继承

这里thrift的实现是

service Calculator extends shared.SharedService {

  /**
   * A method definition looks like C code. It has a return type, arguments,
   * and optionally a list of exceptions that it may throw. Note that argument
   * lists and exception lists are specified using the exact same syntax as
   * field lists in struct or exception definitions.
   */

   void ping(),

   i32 add(1:i32 num1, 2:i32 num2),

   i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),

   /**
    * This method has a oneway modifier. That means the client only makes
    * a request and does not listen for any response at all. Oneway methods
    * must be void.
    */
   oneway void zip()

}

这里是Calculator继承了shared模块中的SharedService。然后go中的实现是

type Calculator interface {
	shared.SharedService
	//Ahh, now onto the cool part, defining a service. Services just need a name
	//and can optionally inherit from another service using the extends keyword.

	// A method definition looks like C code. It has a return type, arguments,
	// and optionally a list of exceptions that it may throw. Note that argument
	// lists and exception lists are specified using the exact same syntax as
	// field lists in struct or exception definitions.
	Ping(ctx context.Context) (_err error)
	// Parameters:
	//  - Num1
	//  - Num2
	Add(ctx context.Context, num1 int32, num2 int32) (_r int32, _err error)
	// Parameters:
	//  - Logid
	//  - W
	Calculate(ctx context.Context, logid int32, w *Work) (_r int32, _err error)
	// This method has a oneway modifier. That means the client only makes
	// a request and does not listen for any response at all. Oneway methods
	// must be void.
	Zip(ctx context.Context) (_err error)
}

嗯在go中继承就是这么简单,我看注释中也是这个意思,然后其他的就是和前面说的SharedService一样。
生成client,process,arg,result等一些结构体和响应的方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/365848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

逆向-还原代码之max 再画堆栈图 (Interl 64)

// source code #include <stdio.h> void max(int * a, int * b) { if (*a < *b) *a *b; } int main() { int a 5, b 6; max(&a, &b); printf("a, b max %d\n", a); return 0; } // 再画堆栈图 下周一&#xff08;2.27…

JavaEE简单示例——MyBatis关联映射

简单介绍&#xff1a; 在我们之前的案例中&#xff0c;我们进行了简单查询&#xff0c;条件产村&#xff0c;动态SQL的条件查询&#xff0c;但是这些操作都是在一张表中进行的&#xff0c;而在我们之前学习MySQL中还有一个很重要的操作就是多表查询操作&#xff0c;也就是说通…

图像亮度调整

非线性方式 调整图像的方法有很多&#xff0c;最常用的方法就是对图像像素点的R、G、B三个分量同时进行增加&#xff08;减少&#xff09;某个值&#xff0c;达到调整亮度的目的。即改变图像的亮度&#xff0c;实际就是对像素点的各颜色分量值做一个平移。这种方法属于非线性的…

适用于产研团队协作工具有哪些?盘点6大类协同办公软件

团队协作工具在提高团队协作效率、质量和灵活性&#xff0c;降低成本等方面都有着不小的作用。而根据协作内容、团队等特点的不同&#xff0c;团队协作工具可以分为多种类型&#xff0c;常见的包括&#xff1a;即时通讯工具&#xff0c;用于实时交流和沟通&#xff0c;其中又可…

SpringBoot整合JPA+人大金仓(kingbase8)

陈老老老板&#x1f9b8;&#x1f468;‍&#x1f4bb;本文专栏&#xff1a;国产数据库-人大金仓&#xff08;kingbase8&#xff09;&#xff08;主要讲一些人大金仓数据库相关的内容&#xff09;&#x1f468;‍&#x1f4bb;本文简述&#xff1a;本文讲一下Jpa框架整合人大金…

Spring Cloud Nacos源码讲解(三)- Nacos客户端实例注册源码分析

Nacos客户端实例注册源码分析 实例客户端注册入口 流程图&#xff1a; 实际上我们在真实的生产环境中&#xff0c;我们要让某一个服务注册到Nacos中&#xff0c;我们首先要引入一个依赖&#xff1a; <dependency><groupId>com.alibaba.cloud</groupId><…

Bootstrap入门到精通(最全最详细)

文章目录前言一、Bootstrap是什么&#xff1f;二、Bootstrap安装方式一&#xff1a;将压缩包下载到本地引入使用方式二&#xff1a;使用Bootstrap官方cdn二.Bootstrap容器下面是屏幕宽度在不同大小时不同容器的显示状态三.Bootstrap栅格系统bootstrap网格系统有以下六个类网格系…

上岸!选择你的隐私计算导师!

开放隐私计算 开放隐私计算开放隐私计算OpenMPC是国内第一个且影响力最大的隐私计算开放社区。社区秉承开放共享的精神&#xff0c;专注于隐私计算行业的研究与布道。社区致力于隐私计算技术的传播&#xff0c;愿成为中国 “隐私计算最后一公里的服务区”。183篇原创内容公众号…

剑指 Offer 55 - I. 二叉树的深度

摘要 剑指 Offer 55 - I. 二叉树的深度 一、深度优先搜索 如果我们知道了左子树和右子树的最大深度l和r&#xff0c;那么该二叉树的最大深度即为&#xff1a;max(l,r)1。 而左子树和右子树的最大深度又可以以同样的方式进行计算。因此我们可以用「深度优先搜索」的方法来计…

JTT808jt1078

List item 前言 交通部与2016年10月份推出了JT/T 1078-2016标准&#xff0c;全称是<道路运输车辆卫星定位系统视频通信协议> 实时音视频传输指令 实时音视频传输请求 消息 I&#xff24;&#xff1a;&#xff10;x9101。 报文类型&#xff1a;信令数据报文。 平台向终…

C语言深入知识——(1)整形数据和浮点数据的存储

1、数据类型的介绍 类型的意义&#xff1a; 使用对应类型能开辟对应内存空间的大小&#xff08;使用范围&#xff09;还有C语言对待不同类型&#xff0c;会采用不同的内存空间视角来看待一个数据 C语言中类型的基本归类&#xff1a; 整型&#xff08;内置类型&#xff09;浮点…

SAP ABAP——SAP简介(六)【ABAP技术栈简介】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计专业大二本科在读&#xff0c;阿里云社区专家博主&#xff0c;华为云社区云享专家&#xff0c;CSDN SAP应用技术领域新兴创作者。   在学习工…

黑吃黑的 Prynt Stealer 在恶意软件中嵌入后门

窃密对于网络犯罪来说&#xff0c;始终都是不可缺少的一部分。攻击者可以通过窃密获取更多信息&#xff0c;来判断攻击目标的价值高低&#xff0c;从而最大化自己的利益。为了使技术不太高的普通攻击者也能够使用&#xff0c;包括 Prynt Stealer 在内的信息窃取类恶意软件通常都…

工赋开发者社区 | 工业数字孪生:西门子工业网络与设备虚拟调试案例(TIA+MCD+SINETPLAN)

PART1案例背景及基本情况新生产系统的设计和实施通常是耗时且高成本的过程&#xff0c;完成设计、采购、安装后&#xff0c;在移交生产运行之前还需要一个阶段&#xff0c;即调试阶段。如果在开发过程中的任何地方出现了错误而没有被发现&#xff0c;那么每个开发阶段的错误成本…

Linux服务:Nginx服务重写功能

目录 一、重写功能 1、重写功能作用 2、rewrite指令 ①if指令 ②return指令 ③ set指令 ④break指令 3、rewrite标志 ①redirect标志 ②permanent标志 ③break标志 ④last标志 ⑤rewrite标志实验 一、重写功能 1、重写功能作用 重写功能(rewrite)用于实现URL的重…

CentOS 8利用Apache安装部署下载服务器

1&#xff1a;部署的目的是做一个类似下面开源镜像网站&#xff0c;把一些软件或者资料上传到服务器上面&#xff0c;减少用户在互联网上下载资料&#xff0c;提高效率&#xff0c;减少病毒。 2&#xff1a;使用下面的命令配置本机的IP地址主机名等信息。后期使用IP地址进行访问…

CRF条件随机场 | 关键原理+面试知识点

&#x1f604; CRF之前跟人生导师&#xff1a;李航学习过&#xff0c;这里结合自己的理解&#xff0c;精简一波CRF&#xff0c;总结一下面试中高频出现的要点。个人觉得没网上说的那么复杂&#xff0c;我看网上很大部分都是一长篇先举个例子&#xff0c;然后再说原理。没必要原…

webservice接口开发详解(.Net)

环境&#xff1a;win10 工具:Visual Studio2015 语言&#xff1a;vb.net WebService: 1.打开vs2015&#xff0c;新建visual basic项目&#xff0c;选择ASP.NET Web应用程序&#xff0c;单击确定 2.右键解决方案&#xff0c;添加新建项-Web-Web 服务(ASMX) 3.生成的WebServi…

Qt QMAKE_MSC_VER

文章目录摘要修改conf文件参考链接关键字&#xff1a; Qt、 QMAKE_MSC_VER 、 conf、 version、 关键字5摘要 今天在又有了新的小项目需要CV一下&#xff0c;但是第三方提供的是COM组件的库&#xff0c;所以第一步还是老实使用VS版本的Qt 来开发&#xff0c;以防不测&#xf…

3个月,入门网络安全并找到工作

在我进入大学之前&#xff0c;我一直对计算机感兴趣。虽然只是考了一个一般大学&#xff0c;但是选专业的时候还是选了计算机专业。 本来以为自己会在大学里学到很多有用的知识&#xff0c;并且能够很快找到一份好工作。但是&#xff0c;事实并不是这样。在大学期间&#xff0c…