Go语言中的byte和rune

Go语言中byterune实质上就是uint8int32类型。byte用来强调数据是raw data,而不是数字;而rune用来表示Unicodecode point参考规范

uint8       the set of all unsigned  8-bit integers (0 to 255)
int32       the set of all signed 32-bit integers (-2147483648 to 2147483647)

byte        alias for uint8
rune        alias for int32

可以通过下面程序验证:

package main

import "fmt"

func byteSlice(b []byte) []byte {
    return b
}

func runeSlice(r []rune) []rune {
    return r
}

func main() {
    b := []byte{0, 1}
    u8 := []uint8{2, 3}
    fmt.Printf("%T %T \n", b, u8)
    fmt.Println(byteSlice(b))
    fmt.Println(byteSlice(u8))

    r := []rune{4, 5}
    i32 := []int32{6, 7}
    fmt.Printf("%T %T \n", r, i32)
    fmt.Println(runeSlice(r))
    fmt.Println(runeSlice(i32))
}

执行结果如下:

[]uint8 []uint8
[0 1]
[2 3]
[]int32 []int32
[4 5]
[6 7]

参考资料:
Difference between []uint8 && []byte (Golang Slices)

 

Go语言的类型转换

以下摘自The Go Programming Language

For every type T, there is a corresponding conversion operation T(x) that converts the value x to type T. A conversion from one type to another is allowed if both have the same underlying type, or if both are unnamed pointer types that point to variables of the same underlying type; these conversions change the type but not the representation of the value. If x is assignable to T, a conversion is permitted but is usually redundant.

Conversions are also allowed between numeric types, and between string and some slice types. These conversions may change the representation of the value. For instance, converting a floating-point number to an integer discards any fractional part, and converting a string to a []byte slice allocates a copy of the string data. In any case, a conversion never fails at run time.

 

Go语言的函数返回多个值

以下摘自The Go Programming Language

Often, functions use these additional results to indicate some kind of error, either by returning an error as in the call to os.Open, or a bool, usually called ok. If a map lookup, type assertion, or channel receive appears in an assignment in which two results are expected, each produces an additional boolean result:
v, ok = m[key] // map lookup
v, ok = x.(T) // type assertion
v, ok = <-ch // channel receive
As with variable declarations, we can assign unwanted values to the blank identifier:
_, err = io.Copy(dst, src) // discard byte count
_, ok = x.(T)

map查找,类型断言和从channel接收数据都会返回两个值,其中一个是表示成功或失败的布尔值。同变量定义一样,不想要的值可以赋给_

 

Go语言的new函数

以下摘自The Go Programming Language

Each call to new returns a distinct variable with a unique address:
p := new(int)
q := new(int)
fmt.Println(p == q) // “false”
There is one exception to this rule: two variables whose type carries no information and is therefore of size zero, such as struct{} or [0]int, may, depending on the implementation, have the same address.
The new function is relatively rarely used because the most common unnamed variables are of struct types, for which the struct literal syntax is more flexible.

Since new is a predeclared function, not a keyword, it’s possible to redefine the name for something else within a function, for example:
func delta(old, new int) int { return new – old }
Of course, within delta, the built-in new function is unavailable.

 

Go语言的变量定义

以下摘自The Go Programming Language

A var declaration creates a variable of a particular type, attaches a name to it, and sets its initial value. Each declaration has the general form
var name type = expression
Either the type or the = expression part may be omitted, but not both. If the type is omitted, it is determined by the initializer expression. If the expression is omitted, the initial value is the zero value for the type, which is 0 for numbers, false for booleans, “” for strings, and nil for interfaces and reference types (slice, pointer, map, channel, function). The zero value of an aggregate type like an array or a struct has the zero value of all of its elements or fields.

short variable declarations are used to declare and initialize the majority of local variables. A var declaration tends to be reserved for local variables that need an explicit type that differs from that of the initializer expression, or for when the variable will be assigned a value later and its initial value is unimportant:
i := 100 // an int
var boiling float64 = 100 // a float64
var names []string
var err error
var p Point

关于“A var declaration tends to be reserved for local variables that need an explicit type that differs from that of the initializer expression,”的理解:var boiling float64 = 100如果使用i := 100的形式来定义,则会认为iint,而不是float

Go语言的“http.Handle”和“http.HandleFunc”

Go语言中http package包含HandleHandleFunc两个函数:

func Handle

func Handle(pattern string, handler Handler)
Handle registers the handler for the given pattern in the DefaultServeMux. The documentation for ServeMux explains how patterns are matched.

func HandleFunc

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
HandleFunc registers the handler function for the given pattern in the DefaultServeMux. The documentation for ServeMux explains how patterns are matched.

Handle函数的handler参数是个interface

type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
}

HandleFunchandler参数就是一个原型为func(ResponseWriter, *Request)的函数。

参考下例(使用Handle):

package main
import (
    "net/http"
    "log"
)

type httpServer struct {
}

func (server httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(r.URL.Path))
}

func main() {
    var server httpServer
    http.Handle("/", server)
    log.Fatal(http.ListenAndServe("localhost:9000", nil))
}

使用HandleFunc

package main
import (
    "net/http"
    "log"
)

func main() {
    http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request){
        w.Write([]byte(r.URL.Path))
    })
    log.Fatal(http.ListenAndServe("localhost:9000", nil))
}

根据The Go Programming Language

A handler pattern that ends with a slash matches any URL that has the pattern as a prefix. Behind the scenes, the server runs the handler for each incoming request in a separate goroutine so that it can serve multiple requests simultaneously.

因此,如果http.Handlehttp.HandleFunc所指定的handle pattern是“/”,则匹配所有的pattern;而“/foo/”则会匹配所有“/foo/*”。

Kubernetes笔记(6)—— kubectl代码分析(1)

kubectl实际运行的函数(k8s.io/kubernetes/pkg/kubectl/app/kubectl.go):

func Run() error {
    cmd := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)
    return cmd.Execute()
}

NewKubectlCommand的代码(k8s.io/kubernetes/pkg/kubectl/cmd/cmd.go):

// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
    // Parent command to which all subcommands are added.
    cmds := &cobra.Command{
        Use:   "kubectl",
        Short: "kubectl controls the Kubernetes cluster manager",
        Long: `kubectl controls the Kubernetes cluster manager.

Find more information at https://github.com/kubernetes/kubernetes.`,
        Run: runHelp,
        BashCompletionFunction: bash_completion_func,
    }

    f.BindFlags(cmds.PersistentFlags())

    // From this point and forward we get warnings on flags that contain "_" separators
    cmds.SetGlobalNormalizationFunc(util.WarnWordSepNormalizeFunc)

    cmds.AddCommand(NewCmdGet(f, out))
    cmds.AddCommand(NewCmdDescribe(f, out))
    cmds.AddCommand(NewCmdCreate(f, out))
    ......
    return &cmds
}

所以cmd := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)得到的cmd是一个指向cobra.Command的指针。

cmdutil.NewFactory代码(k8s.io/kubernetes/pkg/kubectl/cmd/util/factory.go):

// NewFactory creates a factory with the default Kubernetes resources defined
// if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig.
// if optionalClientConfig is not nil, then this factory will make use of it.
func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
    mapper := kubectl.ShortcutExpander{RESTMapper: api.RESTMapper}

    flags := pflag.NewFlagSet("", pflag.ContinueOnError)
    flags.SetNormalizeFunc(util.WarnWordSepNormalizeFunc) // Warn for "_" flags

    generators := map[string]kubectl.Generator{
        "run/v1":                          kubectl.BasicReplicationController{},
        "run-pod/v1":                      kubectl.BasicPod{},
        "service/v1":                      kubectl.ServiceGeneratorV1{},
        "service/v2":                      kubectl.ServiceGeneratorV2{},
        "horizontalpodautoscaler/v1beta1": kubectl.HorizontalPodAutoscalerV1Beta1{},
        "deployment/v1beta1":              kubectl.DeploymentV1Beta1{},
        "job/v1beta1":                     kubectl.JobV1Beta1{},
    }

    clientConfig := optionalClientConfig
    if optionalClientConfig == nil {
        clientConfig = DefaultClientConfig(flags)
    }

    clients := NewClientCache(clientConfig)

    return &Factory{
        ......
    }

因为cmdutil.NewFactory(nil)参数为nil,所以调用的是DefaultClientConfig函数。

clientcmd.ClientConfig定义在k8s.io/kubernetes/pkg/client/unversioned/clientcmd/client_config.go文件:

// ClientConfig is used to make it easy to get an api server client
type ClientConfig interface {
    // RawConfig returns the merged result of all overrides
    RawConfig() (clientcmdapi.Config, error)
    // ClientConfig returns a complete client config
    ClientConfig() (*client.Config, error)
    // Namespace returns the namespace resulting from the merged
    // result of all overrides and a boolean indicating if it was
    // overridden
    Namespace() (string, bool, error)
}

DefaultClientConfig代码(k8s.io/kubernetes/pkg/kubectl/cmd/util/factory.go):

func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
    loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
    flags.StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")

    overrides := &clientcmd.ConfigOverrides{}
    flagNames := clientcmd.RecommendedConfigOverrideFlags("")
    // short flagnames are disabled by default.  These are here for compatibility with existing scripts
    flagNames.ClusterOverrideFlags.APIServer.ShortName = "s"

    clientcmd.BindOverrideFlags(overrides, flags, flagNames)
    clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)

    return clientConfig
}

最后返回一个DeferredLoadingClientConfig结构体(定义在k8s.io/kubernetes/pkg/client/unversioned/clientcmd/merged_client_builder.go):

// DeferredLoadingClientConfig is a ClientConfig interface that is backed by a set of loading rules
// It is used in cases where the loading rules may change after you've instantiated them and you want to be sure that
// the most recent rules are used.  This is useful in cases where you bind flags to loading rule parameters before
// the parse happens and you want your calling code to be ignorant of how the values are being mutated to avoid
// passing extraneous information down a call stack
type DeferredLoadingClientConfig struct {
    loadingRules   *ClientConfigLoadingRules
    overrides      *ConfigOverrides
    fallbackReader io.Reader
}

 

Go语言的const

以下摘自The Go Programming Language

A const declaration gives names to constants, that is, values that are fixed at compile time. The value of a constant must be a number, string, or boolean.

const的值只能是数字,字符串或者布尔值。

 

A constant declaration may specify a type as well as a value, but in the absence of an explicit type, the type is inferred from the expression on the right-hand side.

当定义常量时没有指定其类型时,常量的类型将由等号右边的表达式来决定。

下面是如何定义一组constant

When a sequence of constants is declared as a group, the right-hand side expression may be omitted for all but the first of the group, implying that the previous expression and its type should be used again. For example:
const (
a = 1
b
c = 2
d
)
fmt.Println(a, b, c, d) // “1 1 2 2”

A const declaration may use the constant generator iota, which is used to create a sequence of related values without spelling out each one explicitly. In a const declaration, the value of iota begins at zero and increments by one for each item in the sequence. For example:
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
) This declares Sunday to be 0, Monday to be 1, and so on.

另外,关于untyped constants的定义:

Constants in Go are a bit unusual. Although a constant can have any of the basic data types like int or float64, including named basic types like time.Duration, many constants are not committed to a particular type. The compiler represents these uncommitted constants with much greater numeric precision than values of basic types, and arithmetic on them is more precise than machine arithmetic; you may assume at least 256 bits of precision. There are six flavors of these uncommitted constants, called untyped boolean, untyped integer, untyped rune, untyped floating-point, untyped complex, and untyped string.

只有constant才可能是untyped,变量不可能是untyped

Only constants can be untyped. When an untyped constant is assigned to a variable, as in the first statement below, or appears on the right-hand side of a variable declaration with an explicit type, as in the other three statements, the constant is implicitly converted to the type of that variable if possible.

var f float64 = 3 + 0i // untyped complex -> float64
f = 2 // untyped integer -> float64
f = 1e123 // untyped floating-point -> float64
f = ‘a’ // untyped rune -> float64
The statements above are thus equivalent to these:
var f float64 = float64(3 + 0i)
f = float64(2)
f = float64(1e123)
f = float64(‘a’)

constant之间转化要考虑是否有可能溢出:

Whether implicit or explicit, converting a constant from one type to another requires that the target type can represent the original value. Rounding is allowed for real and complex floating-point numbers:

const (
deadbeef = 0xdeadbeef // untyped int with value 3735928559
a = uint32(deadbeef) // uint32 with value 3735928559
b = float32(deadbeef) // float32 with value 3735928576 (rounded up)
c = float64(deadbeef) // float64 with value 3735928559 (exact)
d = int32(deadbeef) // compile error: constant overflows int32
e = float64(1e309) // compile error: constant overflows float64
f = uint(-1) // compile error: constant underflows uint )

要注意把untyped constant赋值给变量时,变量类型的选择。

In a variable declaration without an explicit type (including short variable declarations), the flavor of the untyped constant implicitly determines the default type of the variable, as in these examples:

i := 0 // untyped integer; implicit int(0)
r := ‘\000’ // untyped rune; implicit rune(‘\000’)
f := 0.0 // untyped floating-point; implicit float64(0.0)
c := 0i // untyped complex; implicit complex128(0i)

Note the asymmetry: untyped integers are converted to int, whose size is not guaranteed, but untyped floating-point and complex numbers are converted to the explicitly sized types float64 and complex128. The language has no unsized float and complex types analogous to unsized int, because it is very difficult to write correct numerical algorithms without knowing the size of one’s floating-point data types.

To give the variable a different type, we must explicitly convert the untyped constant to the desired type or state the desired type in the variable declaration, as in these examples:

var i = int8(0)
var i int8 = 0

These defaults are particularly important when converting an untyped constant to an interface value since they determine its dynamic type.

fmt.Printf(“%T\n”, 0) // “int”
fmt.Printf(“%T\n”, 0.0) // “float64”
fmt.Printf(“%T\n”, 0i) // “complex128”
fmt.Printf(“%T\n”, ‘\000’) // “int32” (rune)

 

 

Kubernetes笔记(3)—— kubectl和cobra

kubectl是控制k8s clustet manager的命令行工具:

$ kubectl
kubectl controls the Kubernetes cluster manager.

Find more information at https://github.com/kubernetes/kubernetes.

Usage:
  kubectl [flags]
  kubectl [command]

Available Commands:
  get            Display one or many resources
  describe       Show details of a specific resource or group of resources
......

kubectl使用了cobra这个项目作为构建命令行的工具,它包含commandsargsflags的概念:

Commands represent actions, Args are things and Flags are modifiers for those actions.

The pattern to follow is APPNAME VERB NOUN --ADJECTIVE. or APPNAME COMMAND ARG --FLAG

举个例子:

$ kubectl get node --v=10

kubectlappnamegetcommandnodearg--v=10flag