golangタイプ断言の使用(Type Asertion)
22993 ワード
第一部分
まずは、自https://studygolang.com/articles/3314断言の基本的な紹介
golangの言語は、断言の機能を提供しています。golangのすべてのプログラムがinterface{}のインターフェースを実現しているということは、すべてのタイプがstring、int、int 64、さらにはカスタムのstructタイプまでがこれに対してinterface{}のインターフェースを持っているということであり、このやり方はjavaのObjectタイプと比較的似ている。一つのデータがfunc func Name(interface{}によって伝えられたとき、つまりこのパラメータが自動的にinterface{}に変換されるタイプを意味します。
下記のコードのように:
cannot convert a(type interface{}to type string:need type astertion
この時、全体の転化過程はタイプの断言が必要であることを意味する。タイプには次のような種類があります。
1)直接に言い切る
var a interface{}
fmt.Println(「Where are you,Jonny?」a.(string)
しかし、失敗は一般にパンティックの発生を招くと言い切る。ですから、パンの発生を防ぐためには、断言する前に一定の判断が必要です。
value,ok:=a.(string)
失敗と断言すれば、okの値はfalseですが、成功okの値はtrueであると断言すれば、valueは期待される正しい値を得ることができます。例:
net/Jsorpc増加get_clientip機能
問題の説明:falcon-agentがホストipの変動を監視できなくなり、初期化インストール時に設定に書いたIPアドレスが現在のリアルIPアドレスと一致しなくなり、エラーが発生したアップロードデータ(古いIPでデータを報告し、新しいIPは監視項目を調べられない)。
解決策:サーバーにagentが大規模に展開されているので、更新が面倒なので、transfer側を修正し、rpc接続から直接にagentのIPを取得することを考えています。
open-falcon/falcon-plus/transferコンポーネントからのrpc関連コード:
初期確立RPC server:open-falcon\falcon-plus\modules\transfer\receiver\rpc.go
重要なステップはJsorpc/server.goの次の関数にあります。
このように、rpcのcalback関数からconnオブジェクトにアクセスし、client IPを取得することができる。
その考えはもとから来ているhttps://github.com/club-codoon/rpcx/blob/630e53bff09759ba2a21644f318907504cfdd98a/_examples/context/server.goの応用方法は以下の通りです。
ただし、この方法には制限があります。次のようなcalbackシーンでは、argsパラメータは[]*sometypeで、sliceです。
もしstructだったら、上述の方法によってプライベートのctxを追加して関連データを保存することができますが、sliceだったら、ctxを一つ置くことができません。そうしたら、sliceをstructtに変えて、json.Unimashelで失敗します。
RPC serverのcalback関数定義:open-falcon\falcon-plus\modules\tranfer\receiver\rpc_transfer.go
一つのworkoundの考えは、jsorpcを一つの私有依存カバンとして取り出し、その中のロジックを変えて、直接にargsをsliceポインタタイプと言い切って、そしてそのデータを遍歴して、client IPをEndpointフィールドに入れます。
【transferのrpc機構はここだけでjsorpcパッケージを使用していますので、このworkoundは他のrpcロジックに影響を与えなくてもいいです。】
転載先:https://www.cnblogs.com/qxxnxxFight/p/11008060.html
まずは、自https://studygolang.com/articles/3314断言の基本的な紹介
golangの言語は、断言の機能を提供しています。golangのすべてのプログラムがinterface{}のインターフェースを実現しているということは、すべてのタイプがstring、int、int 64、さらにはカスタムのstructタイプまでがこれに対してinterface{}のインターフェースを持っているということであり、このやり方はjavaのObjectタイプと比較的似ている。一つのデータがfunc func Name(interface{}によって伝えられたとき、つまりこのパラメータが自動的にinterface{}に変換されるタイプを意味します。
下記のコードのように:
func funcName(a interface{}) string {
return string(a)
}
コンパイラは戻ります。cannot convert a(type interface{}to type string:need type astertion
この時、全体の転化過程はタイプの断言が必要であることを意味する。タイプには次のような種類があります。
1)直接に言い切る
var a interface{}
fmt.Println(「Where are you,Jonny?」a.(string)
しかし、失敗は一般にパンティックの発生を招くと言い切る。ですから、パンの発生を防ぐためには、断言する前に一定の判断が必要です。
value,ok:=a.(string)
失敗と断言すれば、okの値はfalseですが、成功okの値はtrueであると断言すれば、valueは期待される正しい値を得ることができます。例:
value, ok := a.(string)
if !ok {
fmt.Println("It's not ok for type string")
return
}
fmt.Println("The value is ", value)
また、switch文に合わせて判断することもできます。var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
fmt.Printf("unexpected type %T", t) // %T prints whatever type t has
break
case bool:
fmt.Printf("boolean %t
", t) // t has type bool
break
case int:
fmt.Printf("integer %d
", t) // t has type int
break
case *bool:
fmt.Printf("pointer to boolean %t
", *t) // t has type *bool
break
case *int:
fmt.Printf("pointer to integer %d
", *t) // t has type *int
break
}
第二部分net/Jsorpc増加get_clientip機能
問題の説明:falcon-agentがホストipの変動を監視できなくなり、初期化インストール時に設定に書いたIPアドレスが現在のリアルIPアドレスと一致しなくなり、エラーが発生したアップロードデータ(古いIPでデータを報告し、新しいIPは監視項目を調べられない)。
解決策:サーバーにagentが大規模に展開されているので、更新が面倒なので、transfer側を修正し、rpc接続から直接にagentのIPを取得することを考えています。
open-falcon/falcon-plus/transferコンポーネントからのrpc関連コード:
初期確立RPC server:open-falcon\falcon-plus\modules\transfer\receiver\rpc.go
package rpc
import (
"github.com/open-falcon/falcon-plus/modules/transfer/g"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
func StartRpc() {
if !g.Config().Rpc.Enabled {
return
}
addr := g.Config().Rpc.Listen
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
log.Fatalf("net.ResolveTCPAddr fail: %s", err)
}
listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
log.Fatalf("listen %s fail: %s", addr, err)
} else {
log.Println("rpc listening", addr)
}
server := rpc.NewServer()
server.Register(new(Transfer))
for {
conn, err := listener.Accept()
if err != nil {
log.Println("listener.Accept occur error:", err)
continue
}
go server.ServeCodec(jsonrpc.NewServerCodec(conn))
}
}
ここでは、jsorpcの符号化デコーダを使用しており、ここでは、conn内のデータに対してjson.Unimasharlを使用して復号される。重要なステップはJsorpc/server.goの次の関数にあります。
1 type ArgsContext interface {
2 Value(key string) interface{}
3 SetValue(key string, value interface{})
4 }
5
6 func (c *serverCodec) ReadRequestBody(x interface{}) error {
7 if x == nil {
8 return nil
9 }
10 if c.req.Params == nil {
11 return errMissingParams
12 }
13 if args, ok := x.(ArgsContext); ok {
14 args.SetValue("conn", c.c)
15 }
16 // JSON params is array value.
17 // RPC params is struct.
18 // Unmarshal into array containing struct for now.
19 // Should think about making RPC more general.
20 var params [1]interface{}
21 params[0] = x
22 return json.Unmarshal(*c.req.Params, ¶ms)
23 }
1−4行と13−15行は、解析されたargsパラメータにコンテキスト情報を追加することを目的として、新規に判定が追加されました。このように、rpcのcalback関数からconnオブジェクトにアクセスし、client IPを取得することができる。
その考えはもとから来ているhttps://github.com/club-codoon/rpcx/blob/630e53bff09759ba2a21644f318907504cfdd98a/_examples/context/server.goの応用方法は以下の通りです。
1 package main
2
3 import (
4 "fmt"
5 "net"
6
7 "github.com/smallnest/rpcx"
8 )
9
10 type Args struct {
11 A int `msg:"a"`
12 B int `msg:"b"`
13 ctx map[string]interface{}
14 }
15
16 type Reply struct {
17 C int `msg:"c"`
18 }
19
20 func (a *Args) Value(key string) interface{} {
21 if a.ctx != nil {
22 return a.ctx[key]
23 }
24 return nil
25 }
26
27 func (a *Args) SetValue(key string, value interface{}) {
28 if a.ctx == nil {
29 a.ctx = make(map[string]interface{})
30 }
31 a.ctx[key] = value
32 }
33
34 type Arith int
35
36 func (t *Arith) Mul(args *Args, reply *Reply) error {
37 reply.C = args.A * args.B
38 conn := args.Value("conn").(net.Conn)
39 fmt.Printf("Client IP: %s
", conn.RemoteAddr().String())
40 return nil
41 }
42
43 func main() {
44 server := rpcx.NewServer()
45 server.RegisterName("Arith", new(Arith))
46 server.Serve("tcp", "127.0.0.1:8972")
47 }
ただし、この方法には制限があります。次のようなcalbackシーンでは、argsパラメータは[]*sometypeで、sliceです。
もしstructだったら、上述の方法によってプライベートのctxを追加して関連データを保存することができますが、sliceだったら、ctxを一つ置くことができません。そうしたら、sliceをstructtに変えて、json.Unimashelで失敗します。
RPC serverのcalback関数定義:open-falcon\falcon-plus\modules\tranfer\receiver\rpc_transfer.go
import (
"fmt"
cmodel "github.com/open-falcon/falcon-plus/common/model"
cutils "github.com/open-falcon/falcon-plus/common/utils"
"github.com/open-falcon/falcon-plus/modules/transfer/g"
"github.com/open-falcon/falcon-plus/modules/transfer/proc"
"github.com/open-falcon/falcon-plus/modules/transfer/sender"
"strconv"
"time"
"path/filepath"
"crypto/md5"
"io"
"encoding/hex"
)
type Transfer int
type TransferResp struct {
Msg string
Total int
ErrInvalid int
Latency int64
}
func (t *TransferResp) String() string {
s := fmt.Sprintf("TransferResp total=%d, err_invalid=%d, latency=%dms",
t.Total, t.ErrInvalid, t.Latency)
if t.Msg != "" {
s = fmt.Sprintf("%s, msg=%s", s, t.Msg)
}
return s
}
func (t *Transfer) Update(args []*cmodel.MetricValue, reply *cmodel.TransferResponse) error {
return RecvMetricValues(args, reply, "rpc")
}
一つのworkoundの考えは、jsorpcを一つの私有依存カバンとして取り出し、その中のロジックを変えて、直接にargsをsliceポインタタイプと言い切って、そしてそのデータを遍歴して、client IPをEndpointフィールドに入れます。
【transferのrpc機構はここだけでjsorpcパッケージを使用していますので、このworkoundは他のrpcロジックに影響を与えなくてもいいです。】
1 func (c *serverCodec) ReadRequestBody(x interface{}) error {
2 if x == nil {
3 return nil
4 }
5 if c.req.Params == nil {
6 return errMissingParams
7 }
8 // JSON params is array value.
9 // RPC params is struct.
10 // Unmarshal into array containing struct for now.
11 // Should think about making RPC more general.
12 var params [1]interface{}
13 params[0] = x
14 if err := json.Unmarshal(*c.req.Params, ¶ms); err != nil {
15 return err
16 }
17 // fmt.Printf("[jsonrpc]x type is %T
", x)
18 if args, ok := x.(*[]*cmodel.MetricValue); ok {
19 remote_addr := strings.Split(c.c.(net.Conn).RemoteAddr().String(), ":")[0]
20 if remote_addr != "" {
21 for _, v := range *args {
22 v.Endpoint = remote_addr
23 }
24 }
25 }
26 return nil
27 }
転載先:https://www.cnblogs.com/qxxnxxFight/p/11008060.html