【Golang星辰图】Go语言命令行与工具:发掘更多可能性的利器

精通Go语言的命令行工具:深入挖掘扩展库的强大功能

前言

在开发和管理命令行应用程序时,Go语言提供了一些标准库,如flag,但有时我们需要更多的功能和灵活性。为了满足这些需求,Go社区开发了许多强大的扩展库,如cobraviperpflagkingpinurfave/cli。这些扩展库提供了更多的选项和功能,使我们能够更简单地创建、解析和管理命令行标志、子命令和配置。在本文中,我们将介绍这些库的特性和用法,并通过示例代码来演示它们的工作原理。

欢迎订阅专栏:Golang星辰图

文章目录

  • 精通Go语言的命令行工具:深入挖掘扩展库的强大功能
    • 前言
      • [1. flag](#1. flag)
        • [1.1 介绍](#1.1 介绍)
        • [1.2 标准库中的命令行标志包](#1.2 标准库中的命令行标志包)
        • [1.3 使用示例](#1.3 使用示例)
        • [1.4 高级特性](#1.4 高级特性)
          • [1.4.1 自定义类型的标志](#1.4.1 自定义类型的标志)
          • [1.4.2 自定义用法信息](#1.4.2 自定义用法信息)
          • [1.4.3 自定义值验证](#1.4.3 自定义值验证)
      • [2. cobra](#2. cobra)
        • [2.1 介绍](#2.1 介绍)
        • [2.2 创建命令行应用程序](#2.2 创建命令行应用程序)
        • [2.3 子命令和选项](#2.3 子命令和选项)
        • [2.4 生成命令行帮助文档](#2.4 生成命令行帮助文档)
      • [3. viper](#3. viper)
        • [3.1 介绍](#3.1 介绍)
        • [3.2 管理应用程序配置](#3.2 管理应用程序配置)
        • [3.3 配置文件格式](#3.3 配置文件格式)
        • [3.4 使用示例](#3.4 使用示例)
        • [3.5 远程配置管理](#3.5 远程配置管理)
      • [4. pflag](#4. pflag)
        • [4.1 介绍](#4.1 介绍)
        • [4.2 扩展了flag包的功能](#4.2 扩展了flag包的功能)
        • [4.3 使用示例](#4.3 使用示例)
        • [4.4 更灵活的标志定义](#4.4 更灵活的标志定义)
      • [5. kingpin](#5. kingpin)
        • [5.1 介绍](#5.1 介绍)
        • [5.2 创建命令行应用程序](#5.2 创建命令行应用程序)
        • [5.3 子命令和参数](#5.3 子命令和参数)
      • [6. urfave/cli](#6. urfave/cli)
        • [6.1 介绍](#6.1 介绍)
        • [6.2 创建命令行应用程序](#6.2 创建命令行应用程序)
        • [6.3 子命令和参数](#6.3 子命令和参数)
    • 总结

1. flag

1.1 介绍

flag 是 Go 标准库中的命令行标志包。它提供了一种简单的方法来解析命令行参数和选项。使用 flag 包,我们可以定义和解析命令行标志,并使用这些标志来进行相应的操作。

1.2 标准库中的命令行标志包

flag 包提供了多个函数来定义和解析命令行标志。以下是一些常用的函数:

  • flag.String():用于定义一个字符串类型的命令行标志。
  • flag.Int():用于定义一个整数类型的命令行标志。
  • flag.Bool():用于定义一个布尔类型的命令行标志。
1.3 使用示例

下面是一个使用 flag 包的示例代码:

go 复制代码
package main

import (
	"flag"
	"fmt"
)

func main() {
	// 定义命令行标志
	strFlag := flag.String("message", "Hello, World!", "a string flag")

	// 解析命令行标志
	flag.Parse()

	// 打印命令行标志的值
	fmt.Println(*strFlag)
}

在上面的示例中,我们使用 flag.String() 函数定义了一个名为 "message" 的字符串类型命令行标志。然后使用 flag.Parse() 函数来解析命令行标志。最后,通过使用 *strFlag 来访问命令行标志的值,并将其打印出来。

运行该示例程序时,可以通过命令行参数 -message "Hello, Golang!" 来改变输出的值。例如:

sh 复制代码
go run main.go -message "Hello, Golang!"

输出结果为:

Hello, Golang!
1.4 高级特性

除了定义简单的命令行标志外,flag 包还提供了一些高级特性,如自定义类型的标志、自定义用法信息和自定义值验证。以下是一些常用的高级特性:

1.4.1 自定义类型的标志

除了基本的字符串、整数和布尔类型标志,我们还可以使用 flag.Var() 函数来定义自定义类型的命令行标志。这允许我们以更灵活的方式处理命令行输入。以下是一个示例代码:

go 复制代码
package main

import (
	"flag"
	"fmt"
)

type customType struct {
	value string
}

func (c *customType) String() string {
	return c.value
}

func (c *customType) Set(value string) error {
	c.value = value
	return nil
}

func main() {
	customFlag := &customType{}
	flag.Var(customFlag, "custom", "a custom type flag")

	flag.Parse()

	fmt.Println(customFlag.value)
}

在上面的示例中,我们定义了一个 customType 结构体,并实现了 String() 方法和 Set() 方法。通过调用 flag.Var() 并传递一个实现了 flag.Value 接口的对象,我们可以定义一个自定义类型的命令行标志。

1.4.2 自定义用法信息

flag 包默认会生成一份用法信息,它是根据命令行标志定义的顺序和默认值生成的。如果我们想要自定义用法信息,可以使用 flag.Usage 函数进行覆盖。以下是一个示例代码:

go 复制代码
package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	flag.String("message", "Hello, World!", "a string flag")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Custom Usage: \n")
		flag.PrintDefaults()
	}

	flag.Parse()
}

在上面的示例中,我们通过定义 flag.Usage 函数覆盖默认的用法信息。在自定义的 Usage 函数中,我们可以打印自定义的用法信息,并使用 flag.PrintDefaults() 函数打印默认的命令行标志和说明。

1.4.3 自定义值验证

flag 包还提供了 flag.Value 接口的 Valid() 方法,允许我们在解析命令行标志之前对值进行自定义验证。以下是一个示例代码:

go 复制代码
package main

import (
	"errors"
	"flag"
	"fmt"
)

type customFlag struct {
	value string
}

func (c *customFlag) String() string {
	return c.value
}

func (c *customFlag) Set(value string) error {
	if len(value) < 5 {
		return errors.New("value must be at least 5 characters")
	}
	c.value = value
	return nil
}

func (c *customFlag) Valid() error {
	if c.value == "bad" {
		return errors.New("value cannot be 'bad'")
	}
	return nil
}

func main() {
	custom := &customFlag{}
	flag.Var(custom, "custom", "a custom flag")

	flag.Parse()

	fmt.Println(custom.value)
}

在上面的示例中,我们定义了一个实现了 flag.Value 接口的 customFlag 结构体,并在 Set() 方法中进行了长度验证,并在 Valid() 方法中进行了值验证。通过自定义的 Set() 方法和 Valid() 方法,我们可以在解析命令行标志之前进行值的自定义验证。

以上是一些 flag 包的高级特性,通过使用这些特性,我们可以更灵活地处理命令行输入,并进行自定义验证和用法信息。

2. cobra

2.1 介绍

cobra 是一个用于创建命令行应用程序的库。它提供了一种简洁的方式来定义命令、子命令和选项,并支持自动生成命令行帮助文档。

2.2 创建命令行应用程序

要使用 cobra 创建命令行应用程序,我们需要先创建一个根命令,并使用 cobra.Command 函数来定义根命令的属性和动作。以下是一个创建根命令的示例代码:

go 复制代码
package main

import (
	"fmt"

	"github.com/spf13/cobra"
)

func main() {
	rootCmd := &cobra.Command{
		Use:   "myapp",
		Short: "MyApp is a sample command line application",
		Long:  "MyApp is a sample command line application that demonstrates the usage of Cobra library.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Welcome to MyApp!")
		},
	}

	rootCmd.Execute()
}

在上面的示例中,我们创建了一个名为 "myapp" 的根命令,并设置了其简要说明和详细说明。还定义了一个 Run 函数作为根命令的动作,在该函数中打印了欢迎消息。

2.3 子命令和选项

除了根命令之外,我们还可以创建子命令和选项。使用 cobra.CommandAddCommand() 方法可以添加子命令,使用 cobra.CommandFlags() 方法可以添加选项。以下是一个添加子命令和选项的示例代码:

go 复制代码
package main

import (
	"fmt"

	"github.com/spf13/cobra"
)

func main() {
	rootCmd := &cobra.Command{
		Use:   "myapp",
		Short: "MyApp is a sample command line application",
		Long:  "MyApp is a sample command line application that demonstrates the usage of Cobra library.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Welcome to MyApp!")
		},
	}

	childCmd := &cobra.Command{
		Use:   "greet",
		Short: "Greet a person",
		Run: func(cmd *cobra.Command, args []string) {
			name, _ := cmd.Flags().GetString("name")
			fmt.Printf("Hello, %s!\n", name)
		},
	}

	childCmd.Flags().String("name", "World", "name of the person to greet")

	rootCmd.AddCommand(childCmd)

	rootCmd.Execute()
}

在上面的示例中,我们创建了一个名为 "greet" 的子命令,并为其添加了一个名为 "name" 的选项。在子命令的 Run 函数中,通过调用 cmd.Flags().GetString("name") 来获取选项的值。

运行该示例程序时,可以使用以下命令来执行子命令并传递选项值:

sh 复制代码
go run main.go greet --name "Alice"

输出结果为:

Hello, Alice!
2.4 生成命令行帮助文档

一个方便的功能是,cobra 提供了生成命令行帮助文档的支持。通过使用 cobra.Command 结构体中的 LongShortExample 字段,以及标志的 Usage 字段,cobra 可以生成具有结构化布局的命令行帮助文档。以下是一个示例代码:

go 复制代码
package main

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
	Use:   "myapp",
	Short: "MyApp is a sample command line application",
	Long: `MyApp is a sample command line application that demonstrates the usage of Cobra library.
It provides a set of subcommands to perform various tasks.`,
}

var greetCmd = &cobra.Command{
	Use:   "greet",
	Short: "Greet a person",
	Long:  `This command is used to greet a person by specifying their name.`,
	Example: `myapp greet --name Alice`,
	Run: func(cmd *cobra.Command, args []string) {
		name, _ := cmd.Flags().GetString("name")
		fmt.Printf("Hello, %s!\n", name)
	},
}

func init() {
	greetCmd.Flags().String("name", "World", "name of the person to greet")

	rootCmd.AddCommand(greetCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

在上面的示例中,我们使用了 LongShortExampleUsage 字段来定义命令、子命令和选项的描述。当执行 myapp --help 时,cobra 会根据这些描述信息生成帮助文档。

运行该示例程序时,可以使用以下命令来查看命令行帮助文档:

sh 复制代码
go run main.go --help

输出结果为:

MyApp is a sample command line application

Usage:
  myapp [command]

Available Commands:
  greet      Greet a person

Flags:
  -h, --help   help for myapp

Use "myapp [command] --help" for more information about a command.

通过生成的命令行帮助文档,用户可以快速了解命令行应用程序的用法和可用选项。

以上是一些关于 cobra 库的使用示例,通过使用 cobra,我们可以更方便地创建和组织命令行应用程序,并生成具有结构化布局的命令行帮助文档。

3. viper

3.1 介绍

viper 是一个用于管理应用程序配置的库。它支持从多种配置源(例如配置文件、环境变量、命令行标志等)读取配置,并提供了简单的 API 来访问这些配置。使用 viper 可以方便地将配置信息集中管理,而无需手动解析和处理各种配置源。

3.2 管理应用程序配置

要开始使用 viper 管理应用程序配置,我们需要先实例化一个 viper.Viper 对象,并通过调用其 SetConfigFile() 方法来指定配置文件的路径。然后使用 viper.ReadInConfig() 方法来读取配置文件并解析配置。

以下是一个使用 viper 管理应用程序配置的示例代码:

go 复制代码
package main

import (
	"fmt"

	"github.com/spf13/viper"
)

func main() {
	viper.SetConfigFile("config.yaml")
	viper.ReadInConfig()

	value := viper.GetString("key")
	fmt.Println(value)
}

在上面的示例中,我们通过调用 SetConfigFile() 方法来指定配置文件的路径为 "config.yaml",然后使用 ReadInConfig() 方法来读取配置文件。

3.3 配置文件格式

viper 支持多种配置文件格式,包括 JSON、YAML、TOML 等。可以根据配置文件的后缀来自动选择解析方式,也可以使用 viper.SetConfigType() 方法来指定配置文件的类型。

以下是一个使用 YAML 格式的配置文件示例:

yaml 复制代码
key: value
3.4 使用示例

在使用 viper 时,可以通过调用 viper.GetXXX() 系列函数来获取配置项的值,其中 XXX 表示配置项的类型,例如 GetString()GetInt()GetBool() 等。

以下示例代码展示了如何使用 viper 获取配置项的值:

go 复制代码
package main

import (
	"fmt"

	"github.com/spf13/viper"
)

func main() {
	viper.SetConfigFile("config.yaml")
	viper.ReadInConfig()

	strValue := viper.GetString("key")
	intValue := viper.GetInt("number")
	boolValue := viper.GetBool("enabled")

	fmt.Println(strValue)
	fmt.Println(intValue)
	fmt.Println(boolValue)
}

在上面的示例中,我们通过调用 viper.GetString()viper.GetInt()viper.GetBool() 来获取配置项的值,并将其打印出来。

3.5 远程配置管理

除了从本地文件读取配置之外,viper 还支持从远程配置管理系统中读取配置,如 Consul、Etcd 和 ZooKeeper。通过使用适当的 viper 插件,可以将配置存储在远程配置中心,并在运行时从中心获取配置。

以下是一个使用 Consul 存储和获取配置的示例代码:

go 复制代码
package main

import (
	"fmt"

	"github.com/spf13/viper"
	"github.com/spf13/viper/consul"
)

func main() {
	consulConfig := consul.Config{
		Address: "localhost:8500",
		Path:    "myapp/config",
	}

	// 设置适当的 Consul 插件
	viper.AddRemoteProvider("consul", consulConfig.SecretKey, consulConfig.Path)

	// 读取远程配置
	viper.SetConfigType("yaml")
	err := viper.ReadRemoteConfig()
	if err != nil {
		fmt.Printf("Failed to read remote config: %v", err)
	}

	value := viper.GetString("key")
	fmt.Println(value)
}

在上面的示例中,我们创建了一个 consul.Config 对象,并将 Consul 的配置信息传递给它。然后,通过调用 viper.AddRemoteProvider() 来添加适当的 Consul 插件。最后,通过调用 viper.ReadRemoteConfig() 来从远程配置中心读取配置。可以根据实际情况修改 Consul 的地址和路径。

通过使用 viper 的远程配置管理功能,我们可以轻松地将配置信息存储在远程配置中心,并在应用程序运行时从中心获取配置。这使得配置的分发和管理变得更加方便和灵活。

以上是关于 viper 库的使用示例,通过使用 viper,我们可以方便地管理应用程序的配置并从多种配置源中读取配置。无论是本地文件还是远程配置管理系统,viper 都能够满足我们的需求,并提供简单的 API 来访问配置。

4. pflag

4.1 介绍

pflag 是一个扩展了 flag 包的库,提供了更多的功能。它支持更灵活的命令行标志定义和解析,同时还支持子命令和自动生成的帮助文档。

4.2 扩展了flag包的功能

pflag 提供了多个函数来定义和解析命令行标志。它的 API 与 flag 包类似,但增加了一些功能,例如支持短选项、支持布尔类型的标志、支持自定义值验证器等。

以下是一些常用的 pflag 函数:

  • pflag.String():用于定义一个字符串类型的命令行标志。
  • pflag.Int():用于定义一个整数类型的命令行标志。
  • pflag.Bool():用于定义一个布尔类型的命令行标志。
4.3 使用示例

以下是一个使用 pflag 包的示例代码:

go 复制代码
package main

import (
	"fmt"
	"github.com/spf13/pflag"
)

func main() {
	strFlag := pflag.String("message", "Hello, World!", "a string flag")

	pflag.Parse()

	fmt.Println(*strFlag)
}

在上面的示例中,我们使用 pflag.String() 函数定义了一个名为 "message" 的字符串类型命令行标志。然后使用 pflag.Parse() 函数来解析命令行标志。最后,通过使用 *strFlag 来访问命令行标志的值,并将其打印出来。

运行该示例程序时,可以通过命令行参数 --message "Hello, Golang!" 来改变输出的值。例如:

sh 复制代码
go run main.go --message "Hello, Golang!"

输出结果为:

Hello, Golang!
4.4 更灵活的标志定义

除了定义基本的命令行标志外,pflag 还提供了一些更灵活的标志定义选项,如短选项、别名和默认值等。

以下是一个使用 pflag 定义更灵活标志的示例代码:

go 复制代码
package main

import (
	"fmt"
	"github.com/spf13/pflag"
)

func main() {
	var message string
	pflag.StringVarP(&message, "message", "m", "Hello, World!", "a string flag")

	pflag.Parse()

	fmt.Println(message)
}

在上面的示例中,我们使用 pflag.StringVarP() 函数定义了一个名为 "message" 的字符串类型命令行标志。通过使用 P 参数,我们指定了短选项为 "m"。同时,我们还可以为标志设置一个默认值,并提供了一个描述。

运行该示例程序时,可以通过命令行参数 --message "Hello, Golang!"-m "Hello, Golang!" 来改变输出的值。例如:

sh 复制代码
go run main.go --message "Hello, Golang!"

sh 复制代码
go run main.go -m "Hello, Golang!"

输出结果为:

Hello, Golang!

通过使用 pflag 的更灵活标志定义选项,我们可以根据实际需求定义各种类型的标志,并支持更丰富的用户输入方式,提高命令行工具的易用性。

5. kingpin

5.1 介绍

kingpin 是一个用于创建命令行应用程序的库。它提供了一种简单和直观的方式来定义命令、子命令、选项和参数,并支持自动生成的帮助文档。

5.2 创建命令行应用程序

要使用 kingpin 创建命令行应用程序,我们需要先创建一个 kingpin.Application 对象,并通过调用其方法来定义命令、子命令、选项和参数。然后使用 kingpin.Parse() 方法来解析命令行参数。

以下是一个创建命令行应用程序的示例代码:

go 复制代码
package main

import (
	"fmt"
	"gopkg.in/alecthomas/kingpin.v2"
)

func main() {
	app := kingpin.New("myapp", "MyApp is a sample command line application")
	message := app.Flag("message", "a string flag").Default("Hello, World!").String()

	kingpin.Parse()

	fmt.Println(*message)
}

在上面的示例中,我们通过调用 kingpin.New() 函数来创建一个名为 "myapp" 的命令行应用程序,并设置了其描述。然后通过调用 app.Flag() 函数来定义一个名为 "message" 的字符串类型标志。最后,使用 kingpin.Parse() 函数来解析命令行参数。

5.3 子命令和参数

除了根命令之外,kingpin 还支持创建子命令和参数。使用 kingpin.Command 函数可以创建子命令,并使用 kingpin.Arg 函数来定义参数。

以下是一个创建子命令和参数的示例代码:

go 复制代码
package main

import (
	"fmt"
	"gopkg.in/alecthomas/kingpin.v2"
)

func main() {
	app := kingpin.New("myapp", "MyApp is a sample command line application")

	greet := app.Command("greet", "Greet a person")
	name := greet.Arg("name", "Name of the person").Required().String()

	kingpin.Parse()

	fmt.Printf("Hello, %s!\n", *name)
}

在上面的示例中,我们通过调用 app.Command() 函数来创建了一个名为 "greet" 的子命令,并使用 greet.Arg() 函数来定义了一个名为 "name" 的参数。通过调用 kingpin.Parse() 可以解析命令行参数。

运行该示例程序时,可以使用以下命令来执行子命令并传递参数值:

sh 复制代码
go run main.go greet Alice

输出结果为:

Hello, Alice!

使用 kingpin 的子命令和参数功能,我们可以构建更复杂的命令行应用程序,支持多层级的命令和灵活的参数设置。这使得命令行工具可以具备更多的功能和扩展性。

6. urfave/cli

6.1 介绍

urfave/cli 是一个用于创建命令行应用程序的库。它提供了一种简单和直观的方式来定义命令、子命令、选项和参数,并支持自动生成的帮助文档和格式化输出。

6.2 创建命令行应用程序

要使用 urfave/cli 创建命令行应用程序,我们需要先创建一个 cli.App 对象,并通过调用其方法来定义命令、子命令、选项和参数。然后使用 cli.Run() 方法来运行应用程序。

以下是一个创建命令行应用程序的示例代码:

go 复制代码
package main

import (
	"fmt"
	"github.com/urfave/cli"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "myapp"
	app.Usage = "MyApp is a sample command line application"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "message",
			Value: "Hello, World!",
			Usage: "a string flag",
			EnvVar: "MESSAGE",
		},
	}

	app.Action = func(c *cli.Context) error {
		message := c.String("message")
		fmt.Println(message)
		return nil
	}

	app.Run(os.Args)
}

在上面的示例中,我们通过调用 cli.NewApp() 函数来创建一个名为 "myapp" 的命令行应用程序,并设置了其描述。然后通过定义 cli.StringFlag 类型的标志来定义一个名为 "message" 的字符串标志。接着,通过设置 app.Action 为一个函数来定义应用程序的操作,在操作中打印出标志的值。

运行该示例程序时,可以通过命令行参数 --message "Hello, Golang!" 来改变输出的值。例如:

sh 复制代码
go run main.go --message "Hello, Golang!"

输出结果为:

Hello, Golang!
6.3 子命令和参数

urfave/cli 还支持创建子命令和参数。使用 cli.Command 函数可以创建子命令,并使用 cli.Args 函数来定义参数。

以下是一个创建子命令和参数的示例代码:

go 复制代码
package main

import (
	"fmt"
	"github.com/urfave/cli"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "myapp"
	app.Usage = "MyApp is a sample command line application"

	app.Commands = []cli.Command{
		{
			Name:    "greet",
			Aliases: []string{"g"},
			Usage:   "Greet a person",
			Action: func(c *cli.Context) error {
				name := c.Args().Get(0)
				fmt.Printf("Hello, %s!\n", name)
				return nil
			},
		},
	}

	app.Run(os.Args)
}

在上面的示例中,我们通过调用 cli.Command 函数来创建一个名为 "greet" 的子命令,并使用 cli.Args 函数来定义一个参数。在子命令的 Action 中,可以通过 c.Args().Get(0) 来获取参数的值。

运行该示例程序时,可以使用以下命令来执行子命令并传递参数值:

sh 复制代码
go run main.go greet Alice

输出结果为:

Hello, Alice!

通过使用 urfave/cli 的子命令和参数功能,我们可以构建更灵活和多样化的命令行应用程序。无论是简单的命令还是包含子命令和参数的复杂应用程序,urfave/cli 都能够满足我们的需求,并提供简单而直观的 API 和生成帮助文档的功能。

总结

通过本文,我们了解了几个与命令行和工具相关的Go语言扩展库。首先,我们介绍了flag库,它是Go语言标准库中的命令行标志包。然后,我们详细介绍了cobraviperpflagkingpinurfave/cli这些库的功能和用法。我们提供了示例代码来演示如何使用这些库来创建、解析和管理命令行标志、子命令和配置。这些库为我们开发和管理命令行应用程序提供了更多的选项和功能,使我们能够更轻松地构建强大而灵活的应用程序。

相关推荐
gopher95112 分钟前
final,finally,finalize的区别
java·开发语言·jvm
m0_687399848 分钟前
QT combox 前缀匹配
开发语言·数据库·qt
汤兰月16 分钟前
Python中的观察者模式:从基础到实战
开发语言·python·观察者模式
DieSnowK17 分钟前
[C++][第三方库][httplib]详细讲解
服务器·开发语言·c++·http·第三方库·新手向·httplib
火红的小辣椒22 分钟前
PHP反序列化8(phar反序列化)
开发语言·web安全·php
一颗花生米。3 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
问道飞鱼3 小时前
Java基础-单例模式的实现
java·开发语言·单例模式
学习使我快乐013 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
通信仿真实验室4 小时前
(10)MATLAB莱斯(Rician)衰落信道仿真1
开发语言·matlab
勿语&4 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui