网站用什么工具做/优化大师怎么强力卸载

网站用什么工具做,优化大师怎么强力卸载,网件路由器说明书,好看的网页设计模板文章目录 Properties of types and valuesRepresentation of valuesUnderlying types【底层类型】Core types【核心类型】Type identityAssignabilityRepresentabilityMethod sets BlocksDeclarations and scopeLabel scopesBlank identifierPredeclared identifiersExported i…

文章目录

    • Properties of types and values
      • Representation of values
      • Underlying types【底层类型】
      • Core types【核心类型】
      • Type identity
      • Assignability
      • Representability
      • Method sets
    • Blocks
    • Declarations and scope
      • Label scopes
      • Blank identifier
      • Predeclared identifiers
      • Exported identifiers
      • Uniqueness of identifiers
      • Constant declarations
      • Iota
      • Type declarations
        • Alias declarations
        • Type definitions
      • Type parameter declarations
        • Type constraints
        • Satisfying a type constraint
      • Variable declarations
      • Short variable declarations
      • Function declarations
      • Method declarations

Properties of types and values

Representation of values

值的表示。重要!

Values of predeclared types (see below for the interfaces any and error), arrays, and structs are self-contained: Each such value contains a complete copy of all its data, and variables of such types store the entire value. For instance, an array variable provides the storage (the variables) for all elements of the array. The respective zero values are specific to the value’s types; they are never nil.

Non-nil pointer, function, slice, map, and channel values contain references to underlying data which may be shared by multiple values:

  • A pointer value is a reference to the variable holding the pointer base type value.
  • A function value contains references to the (possibly anonymous) function and enclosed variables.
  • A slice value contains the slice length, capacity, and a reference to its underlying array.
  • A map or channel value is a reference to the implementation-specific data structure of the map or channel.

An interface value may be self-contained or contain references to underlying data depending on the interface’s dynamic type. The predeclared identifier nil is the zero value for types whose values can contain references.

When multiple values share underlying data, changing one value may change another. For instance, changing an element of a slice will change that element in the underlying array for all slices that share the array.

Underlying types【底层类型】

Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal【类型字面值】, the corresponding underlying type is T itself. Otherwise, T’s underlying type is the underlying type of the type to which T refers in its declaration.

注意:因为接口类型在类型字面值中,所有接口类型的底层类型是接口自身!

For a type parameter that is the underlying type of its type constraint, which is always an interface.

类型参数的底层类型=类型约束的底层类型。由于类型约束是一个接口类型,所以类型参数的底层类型也是接口类型。

type (A1 = stringA2 = A1
)type (B1 stringB2 B1B3 []B1B4 B3
)func f[P any](x P) {}

The underlying type of string, A1, A2, B1, and B2 is string. The underlying type of []B1, B3, and B4 is []B1. The underlying type of P is interface{}.

注意:B3 的底层类型是 []B1 而不是 []string,因为 []B1 是类型字面值!

类型参数 P 的底层类型是 any 的底层类型,any 的底层类型是 interface{}。

Core types【核心类型】

Each non-interface type T has a core type, which is the same as the underlying type of T.

每个非接口类型都有一个核心类型,接口类型不一定有一个核心类型。

An interface T has a core type if one of the following conditions is satisfied:

  1. There is a single type U which is the underlying type of all types in the type set of T; or
  2. the type set of T contains only channel types with identical element type E, and all directional channels have the same direction.

No other interfaces have a core type.

The core type of an interface is, depending on the condition that is satisfied, either:

  1. the type U; or
  2. the type chan E if T contains only bidirectional channels, or the type chan<- E or <-chan E depending on the direction of the directional channels present.

By definition, a core type is never a defined type, type parameter, or interface type.


By construction, an interface’s type set never contains an interface type.

对于非接口类型,它的核心类型是底层类型,而底层类型不可能是定义的类型,类型参数和接口类型。

对于接口类型,因为接口类型的类型集里不会包含一个接口类型,所以接口类型的核心类型不可能是接口类型。接口类型集里所有类型的底层类型也不可能是定义的类型和类型参数。


Examples of interfaces with core types:

type Celsius float32
type Kelvin  float32interface{ int }                          // int
interface{ Celsius|Kelvin }               // float32
interface{ ~chan int }                    // chan int
interface{ ~chan int|~chan<- int }        // chan<- int
interface{ ~[]*data; String() string }    // []*data

Examples of interfaces without core types:

interface{}                               // no single underlying type
interface{ Celsius|float64 }              // no single underlying type
interface{ chan int | chan<- string }     // channels have different element types
interface{ <-chan int | chan<- int }      // directional channels have different directions

Some operations (slice expressions, append and copy) rely on a slightly more loose form of core types which accept byte slices and strings. Specifically, if there are exactly two types, []byte and string, which are the underlying types of all types in the type set of interface T, the core type of T is called bytestring.

Examples of interfaces with bytestring core types:

interface{ int }                          // int (same as ordinary core type)
interface{ []byte | string }              // bytestring
interface{ ~[]byte | myString }           // bytestring

Note that bytestring is not a real type; it cannot be used to declare variables or compose other types. It exists solely to describe the behavior of some operations that read from a sequence of bytes, which may be a byte slice or a string.

Type identity

Two types are either identical or different.

A named type is always different from any other type.


Predeclared types, defined types, and type parameters are called named types【命名类型】. An alias denotes a named type if the type given in the alias declaration is a named type.【注意:类型字面值不是命名类型,比如[]int、struct{} 等是未命名类型】

byte类型和uint8类型是相同的类型,rune类型和int32类型是相同的类型。


Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types. In detail:

  • Two array types are identical if they have identical element types and the same array length.
  • Two slice types are identical if they have identical element types.
  • Two struct types are identical if they have the same sequence of fields, and if corresponding pairs of fields have the same names, identical types, and identical tags, and are either both embedded or both not embedded. Non-exported field names from different packages are always different.

// 包 pkg1
type S1 struct {name stringAge  int
}
// 包 pkg2
type S2 struct {name stringAge  int
}

S1S2 不是相同类型,因为它们的非导出字段 name 来自不同包,被视为不同字段。


  • Two pointer types are identical if they have identical base types.
  • Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.
  • Two interface types are identical if they define the same type set.
  • Two map types are identical if they have identical key and element types.
  • Two channel types are identical if they have identical element types and the same direction.
  • Two instantiated types are identical if their defined types and all type arguments are identical.

Given the declarations

type (A0 = []stringA1 = A0A2 = struct{ a, b int }A3 = intA4 = func(A3, float64) *A0A5 = func(x int, _ float64) *[]stringB0 A0B1 []stringB2 struct{ a, b int }B3 struct{ a, c int }B4 func(int, float64) *B0B5 func(x int, y float64) *A1C0 = B0D0[P1, P2 any] struct{ x P1; y P2 }E0 = D0[int, string]
)

these types are identical:

A0, A1, and []string
A2 and struct{ a, b int }
A3 and int
A4, func(int, float64) *[]string, and A5B0 and C0
D0[int, string] and E0
[]int and []int
struct{ a, b *B5 } and struct{ a, b *B5 }
func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5

B0 and B1 are different because they are new types created by distinct type definitions; 【定义的类型是命名的类型,都和其他类型不同】

func(int, float64) *B0 and func(x int, y float64) *[]string are different because B0 is different from []string; 【B0是一个定义的类型,和其他类型都不同】

and P1 and P2 are different because they are different type parameters. 【类型参数是命名的类型,和其他类型都不同】

D0[int, string] and struct{ x int; y string } are different because the former is an instantiated defined type while the latter is a type literal (but they are still assignable). 【Instantiating a type results in a new non-generic named type。实例化后的类型是一个新的命名的类型,都和其他类型不同】

Assignability

A value x of type V is assignable to a variable of type T (“x is assignable to T”) if one of the following conditions applies【值x的类型是V,变量的类型是T,V和T可能是类型参数】:

  • V and T are identical.
  • V and T have identical underlying types but are not type parameters and at least one of V or T is not a named type. 【 V 和 T 的底层类型(underlying types)相同,且 V 和 T 都不是类型参数(type parameters),并且至少有一个不是命名类型(named type)。】

在赋值规则中,类型参数不能直接参与底层类型的比较,因为:

  • 类型参数的具体类型在编译时才能确定,无法在赋值时静态判断其底层类型是否匹配。
  • 泛型的类型约束(Constraint)已经确保了类型参数的有效性,因此不需要在赋值阶段额外检查。

  • V and T are channel types with identical element types, V is a bidirectional channel, and at least one of V or T is not a named type.
  • T is an interface type, but not a type parameter, and x implements T. 【变量的类型是接口类型,值x实现了这个接口】
  • x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type, but not a type parameter.
  • x is an untyped constant representable by a value of type T.

Additionally, if x’s type V or T are type parameters, x is assignable to a variable of type T if one of the following conditions applies:

  • x is the predeclared identifier nil, T is a type parameter, and x is assignable to each type in T’s type set.
  • V is not a named type, T is a type parameter, and x is assignable to each type in T’s type set. 【??x 怎么可以赋值给多个类型??】
  • V is a type parameter and T is not a named type, and values of each type in V’s type set are assignable to T.

这里不给举个例子,看不明白

Representability

A constant x is representable by a value of type T, where T is not a type parameter, if one of the following conditions applies:

  • x is in the set of values determined by T.
  • T is a floating-point type and x can be rounded to T’s precision without overflow. Rounding uses IEEE 754 round-to-even rules but with an IEEE negative zero further simplified to an unsigned zero. Note that constant values never result in an IEEE negative zero, NaN, or infinity.
  • T is a complex type, and x’s components real(x) and imag(x) are representable by values of T’s component type (float32 or float64).

If T is a type parameter, x is representable by a value of type T if x is representable by a value of each type in T’s type set. 【??这里也不给举个例子,无语。。。】

x                   T           x is representable by a value of T because'a'                 byte        97 is in the set of byte values
97                  rune        rune is an alias for int32, and 97 is in the set of 32-bit integers
"foo"               string      "foo" is in the set of string values
1024                int16       1024 is in the set of 16-bit integers
42.0                byte        42 is in the set of unsigned 8-bit integers
1e10                uint64      10000000000 is in the set of unsigned 64-bit integers
2.718281828459045   float32     2.718281828459045 rounds to 2.7182817 which is in the set of float32 values
-1e-1000            float64     -1e-1000 rounds to IEEE -0.0 which is further simplified to 0.0
0i                  int         0 is an integer value
(42 + 0i)           float32     42.0 (with zero imaginary part) is in the set of float32 values
x                   T           x is not representable by a value of T because0                   bool        0 is not in the set of boolean values
'a'                 string      'a' is a rune, it is not in the set of string values
1024                byte        1024 is not in the set of unsigned 8-bit integers
-1                  uint16      -1 is not in the set of unsigned 16-bit integers
1.1                 int         1.1 is not an integer value
42i                 float32     (0 + 42i) is not in the set of float32 values
1e1000              float64     1e1000 overflows to IEEE +Inf after rounding

Method sets

The method set of a type determines the methods that can be called on an operand of that type. Every type has a (possibly empty) method set associated with it:

  • The method set of a defined type T consists of all methods declared with receiver type T.
  • The method set of a pointer to a defined type T (where T is neither a pointer nor an interface) is the set of all methods declared with receiver *T or T.
  • The method set of an interface type is the intersection of the method sets of each type in the interface’s type set (the resulting method set is usually just the set of declared methods in the interface).

Further rules apply to structs (and pointer to structs) containing embedded fields, as described in the section on struct types. Any other type has an empty method set.

In a method set, each method must have a unique non-blank method name.

Blocks

A block is a possibly empty sequence of declarations and statements within matching brace brackets.

Block         = "{" StatementList "}" .
StatementList = { Statement ";" } .

In addition to explicit blocks in the source code, there are implicit blocks:

  1. The universe block encompasses all Go source text.
  2. Each package has a package block containing all Go source text for that package.
  3. Each file has a file block containing all Go source text in that file.
  4. Each “if”, “for”, and “switch” statement is considered to be in its own implicit block.
  5. Each clause in a “switch” or “select” statement acts as an implicit block.

Blocks nest and influence scoping.

Declarations and scope

重要!

A declaration binds a non-blank identifier to a constant, type, type parameter, variable, function, label, or package. Every identifier in a program must be declared. No identifier may be declared twice in the same block, and no identifier may be declared in both the file and package block.

The blank identifier may be used like any other identifier in a declaration, but it does not introduce a binding and thus is not declared.

In the package block, the identifier init may only be used for init function declarations, and like the blank identifier it does not introduce a new binding.

Declaration  = ConstDecl | TypeDecl | VarDecl .
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .

The scope of a declared identifier is the extent of source text in which the identifier denotes the specified constant, type, variable, function, label, or package.

Go is lexically scoped using blocks:

  1. The scope of a predeclared identifier is the universe block.
  2. The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
  3. The scope of the package name of an imported package is the file block of the file containing the import declaration.
  4. The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body.
  5. The scope of an identifier denoting a type parameter of a function or declared by a method receiver begins after the name of the function and ends at the end of the function body.
  6. The scope of an identifier denoting a type parameter of a type begins after the name of the type and ends at the end of the TypeSpec.
  7. The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
  8. The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.

An identifier declared in a block may be redeclared in an inner block. While the identifier of the inner declaration is in scope, it denotes the entity declared by the inner declaration.

The package clause is not a declaration; the package name does not appear in any scope. Its purpose is to identify the files belonging to the same package and to specify the default package name for import declarations.

Label scopes

Labels are declared by labeled statements and are used in the “break”, “continue”, and “goto” statements. It is illegal to define a label that is never used. In contrast to other identifiers, labels are not block scoped and do not conflict with identifiers that are not labels. The scope of a label is the body of the function in which it is declared and excludes the body of any nested function.

Blank identifier

The blank identifier is represented by the underscore character _. It serves as an anonymous placeholder instead of a regular (non-blank) identifier and has special meaning in declarations, as an operand, and in assignment statements.

Predeclared identifiers

The following identifiers are implicitly declared in the universe block [Go 1.18] [Go 1.21]:

Types:any bool byte comparablecomplex64 complex128 error float32 float64int int8 int16 int32 int64 rune stringuint uint8 uint16 uint32 uint64 uintptrConstants:true false iotaZero value:nilFunctions:append cap clear close complex copy delete imag lenmake max min new panic print println real recover

Exported identifiers

An identifier may be exported to permit access to it from another package. An identifier is exported if both:

  1. the first character of the identifier’s name is a Unicode uppercase letter (Unicode character category Lu); and
  2. the identifier is declared in the package block or it is a field name or method name.

All other identifiers are not exported.

Uniqueness of identifiers

Given a set of identifiers, an identifier is called unique if it is different from every other in the set. Two identifiers are different if they are spelled differently, or if they appear in different packages and are not exported. Otherwise, they are the same.

不同包里定义的标识符即时名字一样也是不同的。

Constant declarations

A constant declaration binds a list of identifiers (the names of the constants) to the values of a list of constant expressions. The number of identifiers must be equal to the number of expressions, and the nth identifier on the left is bound to the value of the nth expression on the right.

ConstDecl      = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] .IdentifierList = identifier { "," identifier } .
ExpressionList = Expression { "," Expression } .

If the type is present, all constants take the type specified, and the expressions must be assignable to that type, which must not be a type parameter. If the type is omitted, the constants take the individual types of the corresponding expressions. If the expression values are untyped constants, the declared constants remain untyped and the constant identifiers denote the constant values. For instance, if the expression is a floating-point literal, the constant identifier denotes a floating-point constant, even if the literal’s fractional part is zero.

const Pi float64 = 3.14159265358979323846
const zero = 0.0         // untyped floating-point constant
const (size int64 = 1024eof        = -1  // untyped integer constant
)
const a, b, c = 3, 4, "foo"  // a = 3, b = 4, c = "foo", untyped integer and string constants
const u, v float32 = 0, 3    // u = 0.0, v = 3.0

Within a parenthesized const declaration list the expression list may be omitted from any but the first ConstSpec. Such an empty list is equivalent to the textual substitution of the first preceding non-empty expression list and its type if any. Omitting the list of expressions is therefore equivalent to repeating the previous list. The number of identifiers must be equal to the number of expressions in the previous list. Together with the iota constant generator this mechanism permits light-weight declaration of sequential values:

const (Sunday = iotaMondayTuesdayWednesdayThursdayFridayPartydaynumberOfDays  // this constant is not exported
)

Iota

Within a constant declaration, the predeclared identifier iota represents successive【连续的】 untyped integer constants. Its value is the index of the respective ConstSpec in that constant declaration, starting at zero. It can be used to construct a set of related constants:

const (c0 = iota  // c0 == 0c1 = iota  // c1 == 1c2 = iota  // c2 == 2
)const (a = 1 << iota  // a == 1  (iota == 0)b = 1 << iota  // b == 2  (iota == 1)c = 3          // c == 3  (iota == 2, unused)d = 1 << iota  // d == 8  (iota == 3)
)const (u         = iota * 42  // u == 0     (untyped integer constant)v float64 = iota * 42  // v == 42.0  (float64 constant)w         = iota * 42  // w == 84    (untyped integer constant)
)const x = iota  // x == 0
const y = iota  // y == 0

By definition, multiple uses of iota in the same ConstSpec all have the same value:

const (bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0  (iota == 0)bit1, mask1                           // bit1 == 2, mask1 == 1  (iota == 1)_, _                                  //                        (iota == 2, unused)bit3, mask3                           // bit3 == 8, mask3 == 7  (iota == 3)
)

This last example exploits the implicit repetition【隐式的重复】 of the last non-empty expression list.

Type declarations

A type declaration binds an identifier, the type name, to a type. Type declarations come in two forms: alias declarations and type definitions.

TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = AliasDecl | TypeDef .
Alias declarations

An alias declaration binds an identifier to the given type [Go 1.9].

AliasDecl = identifier [ TypeParameters ] "=" Type .

Within the scope of the identifier, it serves as an alias for the given type.

type (nodeList = []*Node  // nodeList and []*Node are identical typesPolar    = polar    // Polar and polar denote identical types
)

If the alias declaration specifies type parameters [Go 1.24], the type name denotes a generic alias【泛型别名】. Generic aliases must be instantiated when they are used.

type set[P comparable] = map[P]bool

In an alias declaration the given type cannot be a type parameter.

type A[P any] = P    // illegal: P is a type parameter
Type definitions

A type definition creates a new, distinct type with the same underlying type and operations as the given type and binds an identifier, the type name, to it.

TypeDef = identifier [ TypeParameters ] Type .

The new type is called a defined type. It is different from any other type, including the type it is created from.

type (Point struct{ x, y float64 }  // Point and struct{ x, y float64 } are different typespolar Point                   // polar and Point denote different types
)type TreeNode struct {left, right *TreeNodevalue any
}type Block interface {BlockSize() intEncrypt(src, dst []byte)Decrypt(src, dst []byte)
}

A defined type may have methods associated with it. It does not inherit any methods bound to the given type, but the method set of an interface type or of elements of a composite type remains unchanged:

重要!

// A Mutex is a data type with two methods, Lock and Unlock.
type Mutex struct         { /* Mutex fields */ }
func (m *Mutex) Lock()    { /* Lock implementation */ }
func (m *Mutex) Unlock()  { /* Unlock implementation */ }// NewMutex has the same composition as Mutex but its method set is empty. 
type NewMutex Mutex// The method set of PtrMutex's underlying type *Mutex remains unchanged,
// but the method set of PtrMutex is empty.
type PtrMutex *Mutex// The method set of *PrintableMutex contains the methods
// Lock and Unlock bound to its embedded field Mutex.
type PrintableMutex struct {Mutex
}// MyBlock is an interface type that has the same method set as Block.
type MyBlock Block

Type definitions may be used to define different boolean, numeric, or string types and associate methods with them:

type TimeZone intconst (EST TimeZone = -(5 + iota)CSTMSTPST
)func (tz TimeZone) String() string {return fmt.Sprintf("GMT%+dh", tz)
}

If the type definition specifies type parameters, the type name denotes a generic type. Generic types must be instantiated when they are used.

// 泛型类型
type List[T any] struct {next  *List[T]value T
}

In a type definition the given type cannot be a type parameter.

type T[P any] P    // illegal: P is a type parameterfunc f[T any]() {type L T   // illegal: T is a type parameter declared by the enclosing function
}

A generic type may also have methods associated with it. In this case, the method receivers must declare the same number of type parameters as present in the generic type definition.

// The method Len returns the number of elements in the linked list l.
func (l *List[T]) Len() int  {}

Type parameter declarations

A type parameter list declares the type parameters of a generic function or type declaration. The type parameter list looks like an ordinary function parameter list except that the type parameter names must all be present and the list is enclosed in square brackets rather than parentheses [Go 1.18].

TypeParameters = "[" TypeParamList [ "," ] "]" .
TypeParamList  = TypeParamDecl { "," TypeParamDecl } .
TypeParamDecl  = IdentifierList TypeConstraint .

All non-blank names in the list must be unique. Each name declares a type parameter, which is a new and different named type that acts as a placeholder for an (as of yet) unknown type in the declaration. The type parameter is replaced with a type argument upon instantiation of the generic function or type.

[P any]
[S interface{ ~[]byte|string }]
[S ~[]E, E any]
[P Constraint[int]]
[_ any]

Just as each ordinary function parameter has a parameter type, each type parameter has a corresponding (meta-)type which is called its type constraint.

A parsing ambiguity arises when the type parameter list for a generic type declares a single type parameter P with a constraint C such that the text P C forms a valid expression:

type T[P *C]type T[P (C)]type T[P *C|Q] …
…

上面的类型声明会被解析为一个数组类型的声明,有歧义。

In these rare cases, the type parameter list is indistinguishable from an expression and the type declaration is parsed as an array type declaration. To resolve the ambiguity, embed the constraint in an interface or use a trailing comma:

type T[P interface{*C}]type T[P *C,]

Type parameters may also be declared by the receiver specification of a method declaration associated with a generic type.

Within a type parameter list of a generic type T, a type constraint may not (directly, or indirectly through the type parameter list of another generic type) refer to T.

type T1[P T1[P]]// illegal: T1 refers to itself
type T2[P interface{ T2[int] }]// illegal: T2 refers to itself
type T3[P interface{ m(T3[int])}]// illegal: T3 refers to itself
type T4[P T5[P]]// illegal: T4 refers to T5 and
type T5[P T4[P]]//          T5 refers to T4type T6[P int] struct{ f *T6[P] }     // ok: reference to T6 is not in type parameter list
Type constraints

A type constraint is an interface that defines the set of permissible type arguments for the respective type parameter and controls the operations supported by values of that type parameter [Go 1.18].

TypeConstraint = TypeElem .

If the constraint is an interface literal of the form interface{E} where E is an embedded type element (not a method), in a type parameter list the enclosing interface{ … } may be omitted for convenience:

[T []P]                      // = [T interface{[]P}]
[T ~int]                     // = [T interface{~int}]
[T int|string]               // = [T interface{int|string}]
type Constraint ~int         // illegal: ~int is not in a type parameter list

The predeclared interface type comparable denotes the set of all non-interface types that are strictly comparable [Go 1.18].

Even though interfaces that are not type parameters are comparable, they are not strictly comparable and therefore they do not implement comparable. However, they satisfy comparable.

【接口类型不是严格可比较的,所以接口类型没有实现comparable】


Interface types that are not type parameters are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.

A type is strictly comparable if it is comparable and not an interface type nor composed of interface types. Specifically:

  • ​ Boolean, numeric, string, pointer, and channel types are strictly comparable.
  • ​ Struct types are strictly comparable if all their field types are strictly comparable.
  • ​ Array types are strictly comparable if their array element types are strictly comparable.
  • Type parameters are strictly comparable if all types in their type set are strictly comparable.


A type T implements an interface I if

  • T is not an interface and is an element of the type set of I; or

  • T is an interface and the type set of T is a subset of the type set of I.


int                          // implements comparable (int is strictly comparable)
[]byte                       // does not implement comparable (slices cannot be compared)
interface{}                  // does not implement comparable (see above)
interface{ ~int | ~string }  // type parameter only: implements comparable (int, string types are strictly comparable)
interface{ comparable }      // type parameter only: implements comparable (comparable implements itself)
interface{ ~int | ~[]byte }  // type parameter only: does not implement comparable (slices are not comparable)
interface{ ~struct{ any } }  // type parameter only: does not implement comparable (field any is not strictly comparable)

The comparable interface and interfaces that (directly or indirectly) embed comparable may only be used as type constraints. They cannot be the types of values or variables, or components of other, non-interface types.

Satisfying a type constraint

A type argument T satisfies a type constraint C if T is an element of the type set defined by C; in other words, if T implements C. As an exception, a strictly comparable type constraint may also be satisfied by a comparable (not necessarily strictly comparable) type argument [Go 1.20]. More precisely:

A type T satisfies a constraint C if

  • T implements C; or
  • C can be written in the form interface{ comparable; E }, where E is a basic interface and T is comparable and implements E.
type argument      type constraint                // constraint satisfactionint                interface{ ~int }              // satisfied: int implements interface{ ~int }
string             comparable                     // satisfied: string implements comparable (string is strictly comparable)
[]byte             comparable                     // not satisfied: slices are not comparable
any                interface{ comparable; int }   // not satisfied: any does not implement interface{ int }
any                comparable                     // satisfied: any is comparable and implements the basic interface any
struct{f any}      comparable                     // satisfied: struct{f any} is comparable and implements the basic interface any
any                interface{ comparable; m() }   // not satisfied: any does not implement the basic interface interface{ m() }
interface{ m() }   interface{ comparable; m() }   // satisfied: interface{ m() } is comparable and implements the basic interface interface{ m() }

为什么 any 满足 comparable?

根据规则的第二条,C 可以写成 interface{ comparable; E },其中 E 是一个基本接口。对于 comparable,它可以看作 interface{ comparable; any },因为 any 是一个基本接口。any 是 comparable 的,并且实现了 any,因此 any 满足 comparable 约束。

为什么 comparable 可以写成 interface{ comparable; any }?
按照接口类型的类型集定义: interface{ comparable; any } 的类型集是 comparable 和 any 类型集的交集,由于any类型集是所有的非接口类型,所以它们的交集就是 comparable 的类型集。由于 interface{ comparable; any } 和 comparable 的类型集相同,它们是相同的类型【按照接口类型是否相同的定义】!


Because of the exception in the constraint satisfaction rule, comparing operands of type parameter type may panic at run-time (even though comparable type parameters are always strictly comparable).

Variable declarations

A variable declaration creates one or more variables, binds corresponding identifiers to them, and gives each a type and an initial value.

VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
var i int
var U, V, W float64
var k = 0
var x, y float32 = -1, -2
var (i       intu, v, s = 2.0, 3.0, "bar"
)
var re, im = complexSqrt(-1)
var _, found = entries[name]  // map lookup; only interested in "found"

If a list of expressions is given, the variables are initialized with the expressions following the rules for assignment statements. Otherwise, each variable is initialized to its zero value.

If a type is present, each variable is given that type. Otherwise, each variable is given the type of the corresponding initialization value in the assignment. If that value is an untyped constant, it is first implicitly converted to its default type; if it is an untyped boolean value, it is first implicitly converted to type bool. The predeclared identifier nil cannot be used to initialize a variable with no explicit type.

var d = math.Sin(0.5)  // d is float64
var i = 42             // i is int
var t, ok = x.(T)      // t is T, ok is bool
var n = nil            // illegal

Implementation restriction: A compiler may make it illegal to declare a variable inside a function body if the variable is never used.

Short variable declarations

A short variable declaration uses the syntax:

ShortVarDecl = IdentifierList ":=" ExpressionList .

It is shorthand for a regular variable declaration with initializer expressions but no types:

"var" IdentifierList "=" ExpressionList .
i, j := 0, 10
f := func() int { return 7 }
ch := make(chan int)
r, w, _ := os.Pipe()  // os.Pipe() returns a connected pair of Files and an error, if any
_, y, _ := coord(p)   // coord() returns three values; only interested in y coordinate

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original. The non-blank variable names on the left side of := must be unique.

field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset)  // redeclares offset
x, y, x := 1, 2, 3                        // illegal: x repeated on left side of :=

Short variable declarations may appear only inside functions. In some contexts such as the initializers for “if”, “for”, or “switch” statements, they can be used to declare local temporary variables.

Function declarations

A function declaration binds an identifier, the function name, to a function.

FunctionDecl = "func" FunctionName [ TypeParameters ] Signature [ FunctionBody ] .
FunctionName = identifier .
FunctionBody = Block .

If the function’s signature declares result parameters, the function body’s statement list must end in a terminating statement.

func IndexRune(s string, r rune) int {for i, c := range s {if c == r {return i}}// invalid: missing return statement
}

If the function declaration specifies type parameters, the function name denotes a generic function. A generic function must be instantiated before it can be called or used as a value.

func min[T ~int|~float64](x, y T) T {if x < y {return x}return y
}

A function declaration without type parameters may omit the body. Such a declaration provides the signature for a function implemented outside Go, such as an assembly routine.

func flushICache(begin, end uintptr)  // implemented externally

Method declarations

A method is a function with a receiver. A method declaration binds an identifier, the method name, to a method, and associates the method with the receiver’s base type.

MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .
Receiver   = Parameters .

The receiver is specified via an extra parameter section preceding the method name. That parameter section must declare a single non-variadic parameter, the receiver. Its type must be a defined type T or a pointer to a defined type T, possibly followed by a list of type parameter names [P1, P2, …] enclosed in square brackets. T is called the receiver base type. A receiver base type cannot be a pointer or interface type and it must be defined in the same package as the method. The method is said to be bound to its receiver base type and the method name is visible only within selectors for type T or *T.

A non-blank receiver identifier must be unique in the method signature. If the receiver’s value is not referenced inside the body of the method, its identifier may be omitted in the declaration. The same applies in general to parameters of functions and methods.

For a base type, the non-blank names of methods bound to it must be unique. If the base type is a struct type, the non-blank method and field names must be distinct.

Given defined type Point the declarations

func (p *Point) Length() float64 {return math.Sqrt(p.x * p.x + p.y * p.y)
}func (p *Point) Scale(factor float64) {p.x *= factorp.y *= factor
}

bind the methods Length and Scale, with receiver type *Point, to the base type Point.

If the receiver base type is a generic type, the receiver specification must declare corresponding type parameters for the method to use. This makes the receiver type parameters available to the method. Syntactically, this type parameter declaration looks like an instantiation of the receiver base type: the type arguments must be identifiers denoting the type parameters being declared, one for each type parameter of the receiver base type. The type parameter names do not need to match their corresponding parameter names in the receiver base type definition, and all non-blank parameter names must be unique in the receiver parameter section and the method signature. The receiver type parameter constraints are implied by the receiver base type definition: corresponding type parameters have corresponding constraints.

type Pair[A, B any] struct {a Ab B
}func (p Pair[A, B]) Swap() Pair[B, A]  {}  // receiver declares A, B
func (p Pair[First, _]) First() First  {}  // receiver declares First, corresponds to A in Pair

If the receiver type is denoted by (a pointer to) an alias, the alias must not be generic and it must not denote an instantiated generic type, neither directly nor indirectly via another alias, and irrespective of pointer indirections.

type GPoint[P any] = Point
type HPoint        = *GPoint[int]
type IPair         = Pair[int, int]func (*GPoint[P]) Draw(P)   {}  // illegal: alias must not be generic
func (HPoint) Draw(P)       {}  // illegal: alias must not denote instantiated type GPoint[int]
func (*IPair) Second() int  {}  // illegal: alias must not denote instantiated type Pair[int, int]

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

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

相关文章

23种设计模式-备忘录(Memento)设计模式

备忘录设计模式 &#x1f6a9;什么是备忘录设计模式&#xff1f;&#x1f6a9;备忘录设计模式的特点&#x1f6a9;备忘录设计模式的结构&#x1f6a9;备忘录设计模式的优缺点&#x1f6a9;备忘录设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是…

某鱼、某宝 sign 签名算法分析记录

【作者主页】&#xff1a;小鱼神1024 【知识星球】&#xff1a;小鱼神的逆向编程圈 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 本文章中所有内容仅供学习交流使用&#xff0c;不用于其…

【C语言】分支与循环(上)

前言&#xff1a;C语言是由顺序结构、选择结构、循环结构组成的结构化的程序设计语言。 那C语言是如何设计和实现这些结构的呢&#xff1f;话不多说&#xff0c;马上开始。 三种结构如图所示&#xff1a; 我们可以使用 if else语句、 switch语句 来实现选择&#xff08;分支&am…

Springboot学习笔记3.20

目录 1.实战篇第一课 我们将会在本次实战中学习到哪些知识点&#xff1f; 开发模式和环境搭建&#xff1a; 注册接口 1.Lombok 2.开发流程 1.controller层&#xff0c;这个层会指明访问路径和要执行的逻辑&#xff1a; 2.我们把返回结果根据接口文档包装成一个类result&a…

全新升级 | Built For You Spring ‘25 发布,Fin 智能客服实现新突破!

图像识别、语音交互、任务自动化&#xff0c;立即体验智能客服蜕变&#xff01; 上周&#xff0c;Intercom 举办了 Built For You Spring 25 发布会&#xff0c;正式揭晓了 AI Agent Fin 的一系列令人振奋的更新。Fin 正在以前所未有的速度革新客户支持模式——它已经成功解决了…

需求导向的K8S网络原理分析:Kube-proxy、Flannel、Calico的地位和作用

最近发现自己似乎从来没学明白过Kubernetes网络通信方案&#xff0c;特开一贴复习总结一下。 在k8s中&#xff0c;每个 Pod 都拥有一个独立的 IP 地址&#xff0c;而且假定所有 Pod 都在一个可以直接连通的、扁平的网络空间中。所以不管它们是否允许在同一个 Node&#xff08;宿…

Vulnhub:Digitalword.local: FALL靶机渗透

将靶机按照图中连接方式打开&#xff0c;fall在virtualBox中打开 信息收集 扫描得ip arp-scan -l 扫描端口 nmap -A -T4 -sV -p- 扫描目录 gobuster dir -u http://192.168.117.160 -x php,txt,html -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt 一个一个…

4、网工软考—VLAN配置—hybird配置

1、实验环境搭建&#xff1a; 2、实验过程 SW1&#xff1a; 先创建vlan2和vlan3 [Huawei-Ethernet0/0/2]port link-type hybrid //hybird端口 [Huawei-Ethernet0/0/2]port hybrid pvid vlan 2 [Huawei-Ethernet0/0/2]port hybrid untagged vlan 10 //撕掉vlan10的标签 …

2025年数智化电商产业带发展研究报告260+份汇总解读|附PDF下载

原文链接&#xff1a;https://tecdat.cn/?p41286 在数字技术与实体经济深度融合的当下&#xff0c;数智化产业带正成为经济发展的关键引擎。 从云南鲜花产业带的直播热销到深圳3C数码的智能转型&#xff0c;数智化正重塑产业格局。2023年数字经济规模突破53.9万亿元&#xff…

【深度学习】【目标检测】【OnnxRuntime】【C++】YOLOV5模型部署

【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV5模型部署 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV5模型部署前言Windows平台搭建依赖环境模型转换--pytorch转onnxONNXRuntime推…

线程同步——读写锁

Linux——线程同步 读写锁 目录 一、基本概念 1.1 读写锁的基本概念 1.2 读写锁的优点 1.3 读写锁的实现 1.4 代码实现 一、基本概念 线程同步中的读写锁&#xff08;Read-Write Lock&#xff09;&#xff0c;也常被称为共享-独占锁&#xff08;Shared-Exclusive Lock&a…

全面解析PRN文件:从原理到可视化的完整指南 【标签打印】

文章目录 一、PRN文件概述二、PRN文件结构深度解析2.1 文件头配置2.1 绘图指令详解2.3 文本处理方案2.4 条码/二维码实现2.5 RFID指令集 三、实战&#xff1a;PRN可视化工具开发3.1 基于Canvas的实现方案3.2 坐标转换关键算法 四、常见问题解决方案4.1 内容偏移问题4.2 中文乱码…

C++:函数(通识版)

一、函数的基础 1.什么是函数&#xff1f;&#xff08;独立的功能单位&#xff09; 函数是C中封装代码逻辑的基本单元&#xff0c;用于执行特定任务。 作用&#xff1a;代码复用、模块化、提高可读性。 2、函数的基本结构 返回类型 函数名(参数列表) {// 函数体return 返回值…

sql注入语句学习

说明 注入漏洞作为登顶过web十大漏洞多次的漏洞&#xff0c;危害性不言而喻&#xff0c;其中sql注入就是注入漏洞常用的手段。其形成的原因是由于web在接收传参数据时&#xff0c;对数据的过滤不够严格&#xff0c;将其带入到数据库查询中&#xff0c;导致用户可以通过传参一些…

云钥科技多通道工业相机解决方案设计

项目应用场景分析与需求挑战 1. 应用场景 ‌目标领域‌&#xff1a;工业自动化检测&#xff08;如精密零件尺寸测量、表面缺陷检测&#xff09;、3D立体视觉&#xff08;如物体建模、位姿识别&#xff09;、动态运动追踪&#xff08;如高速生产线监控&#xff09;等。 ‌核心…

puppeteer+express服务端导出页面为pdf

以下是开发步骤&#xff1a; 1、创建目录 puppeteer_demo 目录&#xff0c;打开目录 初始化项目&#xff08;命令为&#xff1a;npm init -y&#xff09; 页面如&#xff1a; 初始化后&#xff0c;项目目录会出现 package.json 文件 2、安装 puppeteer &#xff0c;使用命令&a…

西域平台商品详情接口设计与实现‌

接口描述&#xff1a; 该接口用于获取西域平台中指定商品的详细信息&#xff0c;包括商品名称、价格、库存、描述、图片等。 点击获取key和secret 接口地址&#xff1a; GET /api/product/detail 请求参数&#xff1a; 参数名 类型 是否必填 描述 productId st…

项目-苍穹外卖(十五) Apache ECharts+数据统计

一、介绍 二、营业额统计 需求分析和设计&#xff1a; Controller: Service: /*** 营业额统计* param begindate* param enddate* return* */Overridepublic TurnoverReportVO turnoverStatistics(LocalDate begindate, LocalDate enddate) {//创建时间集合List<LocalDate&…

体育比分网站开发避坑指南:如何选择靠谱的数据服务商?(10年行业经验总结,避免踩坑!)

作为一家专业的体育比分数据服务商&#xff0c;我们接触过大量客户&#xff0c;发现很多人在开发体育比分网站或接入数据API时&#xff0c;由于选择不靠谱的服务商&#xff0c;导致项目延期、数据延迟、售后无响应、隐性收费等问题&#xff0c;最终影响运营效果&#xff0c;甚至…

离心萃取机在毕赤酵母萃取中的应用

在生物医药领域&#xff0c;毕赤酵母因其高效表达重组蛋白的能力&#xff0c;成为基因工程的“明星宿主”。然而&#xff0c;如何从复杂的发酵体系中高效提取目标产物&#xff0c;一直是行业痛点。离心萃取机的出现&#xff0c;凭借其高速分离、精准提纯的特性&#xff0c;正在…