当前位置: 首页 > news >正文

Go 语言规范学习(3)

文章目录

    • 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]

相关文章:

Go 语言规范学习(3)

文章目录 Properties of types and valuesRepresentation of valuesUnderlying types【底层类型】Core types【核心类型】Type identityAssignabilityRepresentabilityMethod sets BlocksDeclarations and scopeLabel scopesBlank identifierPredeclared identifiersExported i…...

基于django优秀少儿图书推荐网(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;图书推荐网当然不能排除在外。本次开发的优秀少儿图书推荐网是在实际应用和软件工程的开发原理之上&#xff0c;运用Python语言、爬虫技术…...

CS2 DEMO导入blender(慢慢更新咯)

流程&#xff1a;cs2-sourcefilmmaker-blender 工具&#xff1a;cs2tools&#xff0c;cs2manager&#xff0c;blender&#xff0c;blender插件sourceio&#xff0c;source2viewer 导入sfm 工具界面 选择这个 sourceio插件 sourceIO其中新版本导入相机路径不见了&#xff0c…...

SVTAV1函数分析-svt_av1_cost_coeffs_txb

一 函数作用 函数svt_av1_cost_coefss_txb是一个与AV1视频编码相关的函数&#xff0c;主要用于计算变换块(Transform Block)中系数的成本(Cost)。在视频编码中&#xff0c;特被是在AV1编码中&#xff0c;计算系数的成本对于模式决策(Mode Decision)和熵编码(Entropy Coding) 等…...

【Linux加餐-验证UDP:TCP】-windows作为client访问Linux

一、验证UDP-windows作为client访问Linux UDP client样例代码 #include <iostream> #include <cstdio> #include <thread> #include <string> #include <cstdlib> #include <WinSock2.h> #include <Windows.h>#pragma warning(dis…...

qt+opengl 加载三维obj文件

1前面我们已经熟悉了opengl自定义顶点生成一个立方体&#xff0c;并且我们实现了立方体的旋转&#xff0c;光照等功能。下面我们来用opengl来加载一个obj文件。准备我们首先准备一个简单的obj文件&#xff08;head.obj&#xff09;。资源在本页下载 2 在obj文件里面&#xff0c…...

日报日报流量分析

快捷键 CtrlK&#xff0c;选择需要抓包的网卡 CtrlF可以进行关键字搜索 CtrlM&#xff0c;标记数据包 CtrlShiftN跳到标记处 查看包有多少协议Protocol Hierarchy&#xff08;协议分级&#xff09; 搜了一下TCP协议&#xff0c;是互联网最基本的协议&#xff0…...

SQL:CASE WHEN使用详解

文章目录 1. 数据转换与映射2. 动态条件筛选3. 多条件分组统计4. 数据排名与分级5. 处理空值与默认值6. 动态排序 CASE WHEN 语句在 SQL 中是一个非常强大且灵活的工具&#xff0c;除了常规的条件判断外&#xff0c;还有很多巧妙的用法&#xff0c;以下为你详细总结&#xff1a…...

在 Unreal Engine 5 中制作类似《鬼泣5》这样的游戏时,角色在空中无法落地的问题可能由多种原因引起。

系列文章目录 文章目录 系列文章目录前言一、实现步骤二、涉及到的蓝图三、如何把敌人击飞到空中 前言 在 Unreal Engine 5 中制作类似《鬼泣5》这样的游戏时&#xff0c;角色在空中无法落地的问题可能由多种原因引起。 一、实现步骤 角色碰撞设置 确保角色的碰撞组件&…...

mapbox进阶,添加鹰眼图控件

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️mapboxgl-minimap 鹰眼控件二、🍀添加…...

k8s污点与容忍

k8s污点与容忍 k8s污点管理常用命令effect标记值查看污点添加污点删除污点 node污点与容忍污点容忍yaml示例容忍放大基于污点的驱逐驱逐时排除指定服务 设置master调度设置master尽量不调度允许master节点调度pod恢复Master Only状态将node标记为不可调度状态(节点警戒)设置nod…...

算法刷题记录——LeetCode篇(9.1) [第801~810题]

更新时间&#xff1a;2025-03-29 算法题解目录汇总&#xff1a;算法刷题记录——题解目录汇总技术博客总目录&#xff1a;计算机技术系列博客——目录页 优先整理热门100及面试150&#xff0c;不定期持续更新&#xff0c;欢迎关注&#xff01; 801. 使序列递增的最小交换次数…...

AOA与TOA混合定位,MATLAB例程,自适应基站数量,三维空间下的运动轨迹,滤波使用EKF

本代码实现了一个基于 到达角(AOA) 和 到达时间(TOA) 的混合定位算法,结合 扩展卡尔曼滤波(EKF) 对三维运动目标的轨迹进行滤波优化。代码通过模拟动态目标与基站网络,展示了从信号测量、定位解算到轨迹滤波的全流程,适用于城市峡谷、室内等复杂环境下的定位研究。 文…...

【vllm/瞎折腾】在内网wsl上安装vllm并尝试多节点部署(失败了)

目录 说在前面miniconda安装外网创建虚拟环境创建节点一的虚拟环境创建节点二的虚拟环境 内网配置环境配置节点一的环境配置节点二的环境 vllm多节点配置节点一(主节点)配置节点二配置 部署LLM(失败)补充&#xff1a;wsl2设置ulimit补充&#xff1a;wsl安装libcuda补充&#xf…...

Mayo Clinic Platform在人工智能医疗领域的现状及启示意义研究

一、引言 1.1 研究背景与意义 在科技飞速发展的当下,人工智能(AI)已逐渐渗透至各个行业,医疗领域作为关乎人类生命健康的重要领域,也迎来了人工智能技术带来的深刻变革。人工智能医疗,作为人工智能与医疗行业深度融合的产物,正重塑着全球医疗的格局。 从全球范围来看,…...

k8s部署教程

Kubernetes 1. 使用Kubernetes部署Web服务器 ​ 我们的目标是部署三个实例&#xff0c;可以让用户直接访问。三个实例&#xff0c;这样即便一个崩溃了&#xff0c;也还有两个&#xff0c;比较不容易出问题。实际中你要根据自己的业务来判断。也就是说&#xff0c;我们需要一个…...

java基础:常见类和对象

1.常见类和对象&#xff1a; java.lang.Object类&#xff0c;Java中的每个类都直接或间接地继承自Object类&#xff0c;如果没有明确指定一个类继承另一个类&#xff0c;那么它的默认父类就是Object类&#xff1b; 例如多态&#xff1a; package java_jichu;public class ja…...

了解遗传算法的Matlab程序的奥妙之处

老板突然想要了解遗传算法的Matlab程序,我们需要先理清楚他们的需求。首先,老板可能对遗传算法有一定的了解,但不太清楚如何在Matlab中具体实现。他可能是一个学生或者研究人员,需要应用到某个项目中,比如优化问题。老板可能希望得到一个结构清晰的步骤说明,以及具体的代…...

Java学习------源码解析之StringBuilder

1. 介绍 String中还有两个常用的类&#xff0c;StringBuffer和StringBuilder。这两个类都是专门为频繁进行拼接字符串而准备的。最先出现的是StringBuffer&#xff0c;之后到jdk1.5的时候才有了StringBuilder。 2. StringBuilder解析 从这张继承结构图可以看出&#xff1a; S…...

【漫话机器学习系列】163.方差膨胀因子(Variance Inflation Factor, VIF)

方差膨胀因子&#xff08;Variance Inflation Factor, VIF&#xff09;详解 1. 什么是方差膨胀因子&#xff1f; 方差膨胀因子&#xff08;Variance Inflation Factor, VIF&#xff09;是一种用于衡量回归分析中多重共线性&#xff08;Multicollinearity&#xff09;程度的指…...

蓝桥杯省模拟赛 字符串拼接

问题描述 给定四个字符串 a,b,c,d&#xff0c;请将这四个字符串按照任意顺序依次连接拼成一个字符串。 请问拼成的字符串字典序最小是多少&#xff1f; 输入格式 输入四行&#xff0c;每行包含一个字符串。 输出格式 输出一行包含一个字符串&#xff0c;表示答案。 样例…...

前端路由守卫与后端权限验证,仅使用路由守卫是否安全?

前后端分离架构的安全原则 后端必须对所有 API 接口进行权限验证前端仅负责用户界面的重定向安全策略应始终由后端最终决定 问题1&#xff1a;前端设置路由守卫是否可以阻挡用户直接通过URL访问&#xff1f;&#xff1f;&#xff1f; 前端路由守卫&#xff08;如 Vue Router …...

React-nodejs 练习 个人博客

1.主要功能模块&#xff1a; 文章管理&#xff1a;CRUD操作 用户系统&#xff1a;注册、登录、权限控制评论系统&#xff1a;文章评论功能 2.技术栈&#xff1a; 前端&#xff1a;React Ant Design React Router后端&#xff1a;Express MongoDB 通信&#xff1a;RESTful…...

AI三大主义 和 深度学习三大主义

在人工智能&#xff08;AI&#xff09;研究领域&#xff0c;"三大主义"通常指三种核心方法论或思想流派&#xff0c;它们代表了不同的技术路径和哲学观点。以下是主流的划分方式&#xff1a; 1. 符号主义&#xff08;Symbolicism&#xff09; 核心思想&#xff1a;智…...

Linux实现生产者消费者模型(基于阻塞队列)

目录 概念及优势 代码实现 概念及优势 生产者消费者模型是一种用于线程同步的模型&#xff0c;在这个模型中有两种角色&#xff0c;生产者生产数据&#xff0c;消费者消费数据。有三种关系&#xff0c;生产者与生产者&#xff0c;消费者与消费者&#xff0c;生产者与消费者。…...

UE5 UE4 右键/最大化-菜单-不显示/闪/黑色/黑屏--修复方法

先关闭UE5 、UE4 编辑器。 进入这个网站&#xff1a;https://nvidia.custhelp.com/app/answers/detail/a_id/5157 网速慢&#xff0c;换成这个下载&#xff1a;https://download.csdn.net/download/qq_21153225/90546310 下载&#xff1a;mpo_disable.reg 的文件 只双击“mpo…...

[ C语言 ] | 从0到1?

目录 认识计算机语言 C语言 工欲善其事必先利其器 第一个C语言代码 这一些列 [ C语言 ] &#xff0c;就来分享一下 C语言 相关的知识点~ 认识计算机语言 我们说到计算机语言&#xff0c;语言&#xff0c;就是用来沟通的工具&#xff0c;计算机语言呢&#xff1f;就是我们…...

4.训练篇2-毕设篇

resnet # 1. 从 torchvision 中加载预训练的 ResNet18 模型 # pretrainedTrue 表示使用在 ImageNet 上预训练过的参数&#xff0c;学习效果更好 base_model_resnet18 models.resnet18(pretrainedTrue)# 2. 获取 ResNet18 模型中全连接层&#xff08;fc&#xff09;的输入特征…...

Ubuntu 系统中,每日健康检查

一、手动检查命令&#xff08;基础项&#xff09; 1. 系统资源监控 内存使用&#xff1a; free -h # 查看内存和交换空间使用情况 cat /proc/meminfo | grep -i "memavailable" # 查看可用内存CPU 负载&#xff1a; top -n 1 -b | grep "load ave…...

#CX# UVM中的virtual sequence 和 virtual sequencer 的用途

在UVM中,Virtual Sequence(虚拟序列) 的核心用途是协调多个物理Sequencer上的Sequence执行,以实现跨接口、跨组件的复杂事务同步和场景控制。 1. 核心用途 多接口协同测试 当验证场景需要多个接口(如DUT的AXI、I2C、UART接口)同时或按特定顺序发送事务时,Virtual Seque…...

vue:突然发现onok无法使用

const that this;this.$confirm({title: "修改商品提示",content: "如果当前商品存在于商品活动库&#xff0c;则在商品活动库的状态会下架",onOk: function () {that.submitForm();}}); 突然发现 this.$confirm无法进入onok 最终发现是主题冲突&#x…...

开发过程中需要安装的浏览器插件

Vue.js devtools https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?hlzh-CN&utm_sourceext_sidebar ModHeader https://chromewebstore.google.com/detail/modheader-modify-http-hea/idgpnmonknjnojddfkpgkljpfnnfcklj?utm…...

基于javaweb的SpringBoot房屋出租系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

小程序某点餐平台全自动化实现思路

某德基全自动化实现 一、实现思路二、具体步骤1、分析接口2、破解接口3、解决自动支付4、获取订单 三、其他 以下内容仅供学习交流使用 粗略讲解一下思路&#xff0c;要完全实现只靠以下这些内容还是不够的。 一、实现思路 全自动化实现用的是小程序版本。我们首先要分析整个…...

红宝书第二十讲:详解JavaScript的Proxy与Reflect

红宝书第二十讲&#xff1a;详解JavaScript的Proxy与Reflect 资料取自《JavaScript高级程序设计&#xff08;第5版&#xff09;》。 查看总目录&#xff1a;红宝书学习大纲 一、Proxy的作用&#xff1a;给对象戴上“监听耳机” Proxy&#xff08;代理&#xff09;允许你为对象…...

Contactile三轴触觉传感器:多维力感赋能机器人抓取

在非结构化环境中&#xff0c;机器人对物体的精准抓取与操作始终面临巨大挑战。传统传感器因无法全面感知触觉参数&#xff08;如三维力、位移、摩擦&#xff09;&#xff0c;难以适应复杂多变的场景。Contactile推出的三轴触觉力传感器&#xff0c;通过仿生设计与创新光学技术…...

18-动规-子序列中的 k 种字母(中等)

题目 来源 28. 子序列中的 k 种字母&#xff08;第一期模拟笔试&#xff09; 思路 基本分析 子序列的定义 子序列是从原序列中选取部分元素&#xff0c;同时保持这些元素在原序列中的相对顺序所形成的新序列。也就是说&#xff0c;子序列中的元素不需要在原序列中连续出现…...

Lua 数组

Lua 数组 引言 Lua 是一种轻量级、高效的脚本语言&#xff0c;广泛应用于游戏开发、服务器端编程等领域。在 Lua 中&#xff0c;数组是一种非常重要的数据结构&#xff0c;它允许开发者以高效的方式存储和操作一系列数据。本文将详细介绍 Lua 数组的相关知识&#xff0c;包括…...

C 语言的未来:在变革中坚守核心价值

一、从 “古老” 到 “长青”&#xff1a;C 语言的不可替代性 诞生于 20 世纪 70 年代的 C 语言&#xff0c;历经半个世纪的技术浪潮&#xff0c;至今仍是编程世界的 “基石语言”。尽管 Python、Java 等高级语言在应用层开发中占据主流&#xff0c;但 C 语言在系统级编程和资…...

springboot3 基于 logback

1.配置 logging:level:root: ${ROOT_LOG_LEVEL:debug}web: ${ROOT_WEB_LEVEL:info}org.hibernate.orm.jdbc.bind: ${ROOT_SQL_PARAM_LEVEL:info} #打印SQL参数2.基于 logback-spring.xml配置 <?xml version="1.0" encoding="UTF-8"?> <configu…...

网络相关的知识总结1

1.设备可以通过以太网电缆&#xff08;如双绞线&#xff09;连接到交换机的端口&#xff0c;交换机也通过以太网电缆连接到路由器。但是如果距离过远&#xff0c;比如跨国路由器如何连接&#xff1f; 1.专用通信线路&#xff08;如 MPLS、光纤专线&#xff09;&#xff1a;租用…...

Rust vs. Go: 性能测试(2025)

本内容是对知名性能评测博主 Anton Putra Rust vs. Go (Golang): Performance 2025 内容的翻译与整理, 有适当删减, 相关数据和结论以原作结论为准。 再次对比 Rust 和 Go&#xff0c;但这次我们使用的是最具性能优势的 HTTP 服务器库---Hyper&#xff0c;它基于 Tokio 异步运…...

如何使用postman调用多参数接口(包含文件上传)

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 如何使用postman调用包含文件参数的多参数接…...

无人机助力道路智能养护,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建无人机航拍道路交通场景下水泥路面缺陷智能检测识别系统

道路养护是保障交通命脉安全的隐形防线&#xff0c;其重要性不亚于道路建设本身。我国每年因道路病害引发的交通事故占比高达12%&#xff0c;及时修复1平方米的早期裂缝可避免后续数万元的修复成本。在这场与道路病害赛跑的战役中&#xff0c;传统养护模式正遭遇前所未有的挑战…...

28_跨域

目录 promise promise的基本语法 async await try catch promise 静态方法 跨域 跨域的解决方案 1-cors ​编辑 2-jsonp方案 3-代理服务器 promise promise 是一个es6新增的语法 承诺的意思 作用:是专门用来解决回调地狱!!!! promise的基本语法 // 基本语法:// Pr…...

【C#.NET】VS2022创建Web API项目

C# Web API 是一种基于 .NET 平台&#xff08;包括但不限于.NET Framework 和 .NET Core&#xff09;构建 HTTP 服务的框架&#xff0c;用于创建 RESTful Web 服务。REST&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;它利用HTTP协议…...

注意力蒸馏技术

文章目录 摘要abstract论文摘要简介方法预备知识注意力蒸馏损失注意力引导采样 实验结论总结参考文献 摘要 本周阅读了一篇25年二月份发表于CVPR 的论文《Attention Distillation: A Unified Approach to Visual Characteristics Transfer》,论文开发了Attention Distillation…...

Day17 -实例:利用不同语言不同框架的特征 进行识别

前置&#xff1a;我们所需的web站点&#xff0c;都可以利用fofa去搜索&#xff0c;例如&#xff1a;app"flask"这样的语句去找对应的站点&#xff0c;找到后&#xff0c;我们模拟不知道是什么框架&#xff0c;再根据特征去判断它的框架。 ***利用工具可以再去结合大…...

Centos7 安装 TDengine

Centos7 安装 TDengine 1、简介 官网&#xff1a; https://www.taosdata.com TDengine 是一款开源、高性能、云原生的时序数据库&#xff08;Time Series Database, TSDB&#xff09;, 它专为物联网、车联网、工业互联网、金融、IT 运维等场景优化设计。同时它还带有内建的缓…...

DeepSeek调用API访问,使用AnythingLLM建立本地知识库后开放API调用,ApiFox/PostMan调用本地DeepSeek

上篇文章中我们使用AnythingLLM成功在本地部署了DeepSeek的本地知识库&#xff0c;并且上传了几个文件让DeepSeek学习&#xff0c;可点击查看&#xff1a; 本地部署DeepSeek并使用AnythingLLM建立本地知识库全流程&#xff0c;DeepSeek-R1:7b本地安装部署,DeepSeek-R1本地部署…...