跟着实例学Go语言(四)
admin
2024-03-22 07:31:28
0

本教程全面涵盖了Go语言基础的各个方面。一共80个例子,每个例子对应一个语言特性点,非常适合新人快速上手。
教程代码示例来自go by example,文字部分来自本人自己的理解。

本文是教程系列的第四部分,共计20个例子、约1.5万字。

目录

  • 61. Base64 Encoding
  • 62. Reading Files
  • 63. Writing Files
  • 64. Line Filters
  • 65. File Paths
  • 66. Directories
  • 67. Temporary Files and Directories
  • 68. Embed Directive
  • 69. Testing and Benchmarking
  • 70. Command-Line Arguments
  • 71. Command-Line Flags
  • 72. Command-Line Subcommands
  • 73. Environment Variables
  • 74. HTTP Client
  • 75. HTTP Server
  • 76. Context
  • 77. Spawning Processes
  • 78. Exec'ing Processes
  • 79. Signals
  • 80. Exit

61. Base64 Encoding

Go提供了Base64编解码的功能。Base64是将二进制数据转换成可读字符串的编码方式。例如我们用记事本打开jpg文件,会看到一串乱码,这个就是Base64转换后的字符串。Base64提供了64种不同的字符,6位编码表示一个字符。

package mainimport (b64 "encoding/base64""fmt"
)func main() {data := "abc123!?$*&()'-=@~"// 将data底层的byte slice编码成字符串sEnc := b64.StdEncoding.EncodeToString([]byte(data))fmt.Println(sEnc)// 用Base64解码sDec, _ := b64.StdEncoding.DecodeString(sEnc)fmt.Println(string(sDec))fmt.Println()// 用URL兼容的方式编码uEnc := b64.URLEncoding.EncodeToString([]byte(data))fmt.Println(uEnc)// 用URL兼容的方式解码uDec, _ := b64.URLEncoding.DecodeString(uEnc)fmt.Println(string(uDec))
}
$ go run base64-encoding.go
YWJjMTIzIT8kKiYoKSctPUB+
abc123!?$*&()'-=@~YWJjMTIzIT8kKiYoKSctPUB-
abc123!?$*&()'-=@~

62. Reading Files

下面例子展示了读文件的操作。

package mainimport ("bufio""fmt""io""os"
)func check(e error) {if e != nil {panic(e)}
}func main() {// 直接从文件读到byte slicedat, err := os.ReadFile("/tmp/dat")check(err)fmt.Print(string(dat))// 先打开文件,再对file做更复杂的操作f, err := os.Open("/tmp/dat")check(err)// 自己创建缓冲slice来接收读数据。返回的是读到的字节数b1 := make([]byte, 5)n1, err := f.Read(b1)check(err)fmt.Printf("%d bytes: %s\n", n1, string(b1[:n1]))// 偏移到下标为6的地方开始读取。两个参数分别代表:基于基准位置的偏移量、基准位置o2, err := f.Seek(6, 0)check(err)b2 := make([]byte, 2)n2, err := f.Read(b2)check(err)fmt.Printf("%d bytes @ %d: ", n2, o2)fmt.Printf("%v\n", string(b2[:n2]))o3, err := f.Seek(6, 0)check(err)b3 := make([]byte, 2)// ReadAtLeast保证一定读到指定字节数,否则返回错误n3, err := io.ReadAtLeast(f, b3, 2)check(err)fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3))_, err = f.Seek(0, 0)check(err)// bufio包提供了带缓冲的读写并提供一些更简便的操作,这里创建了带缓冲的readerr4 := bufio.NewReader(f)// 获取后面5个字节,但不实际移动指针,类似于队列中的peekb4, err := r4.Peek(5)check(err)fmt.Printf("5 bytes: %s\n", string(b4))f.Close()
}
$ echo "hello" > /tmp/dat
$ echo "go" >>   /tmp/dat
$ go run reading-files.go
hello
go
5 bytes: hello
2 bytes @ 6: go
2 bytes @ 6: go
5 bytes: hello

63. Writing Files

下面例子展示了写文件的操作。

package mainimport ("bufio""fmt""os"
)func check(e error) {if e != nil {panic(e)}
}func main() {d1 := []byte("hello\ngo\n")// 将byte slice写入文件,若文件不存则创建,创建时使用0644代表的权限err := os.WriteFile("/tmp/dat1", d1, 0644)check(err)// 先创建文件,再对file做更复杂的操作f, err := os.Create("/tmp/dat2")check(err)// 将close操作推迟到最后defer f.Close()// 将自己创建的byte slice写入文件d2 := []byte{115, 111, 109, 101, 10}n2, err := f.Write(d2)check(err)fmt.Printf("wrote %d bytes\n", n2)// 直接写入一个字符串n3, err := f.WriteString("writes\n")check(err)fmt.Printf("wrote %d bytes\n", n3)// 写完后需要调用Sync()才能真正写入硬盘f.Sync()// 用bufio创建自带缓冲的writerw := bufio.NewWriter(f)n4, err := w.WriteString("buffered\n")check(err)fmt.Printf("wrote %d bytes\n", n4)// 写完后需要调用Flush(),将缓冲区数据落地w.Flush()}
$ go run writing-files.go 
wrote 5 bytes
wrote 7 bytes
wrote 9 bytes$ cat /tmp/dat1
hello
go
$ cat /tmp/dat2
some
writes
buffered

64. Line Filters

下面例子展示了从标准输入中读取并解析。类似于Java中的Scanner和Linux下的grep、sed命令。

package mainimport ("bufio""fmt""os""strings"
)func main() {// 从标准输入创建scannerscanner := bufio.NewScanner(os.Stdin)for scanner.Scan() {// 默认用空格分隔,每次新读取一段ucl := strings.ToUpper(scanner.Text())fmt.Println(ucl)}if err := scanner.Err(); err != nil {fmt.Fprintln(os.Stderr, "error:", err)os.Exit(1)}
}
$ echo 'hello'   > /tmp/lines
$ echo 'filter' >> /tmp/lines$ cat /tmp/lines | go run line-filters.go
HELLO
FILTER

65. File Paths

下面例子展示了对文件路径的各种操作。

package mainimport ("fmt""path/filepath""strings"
)func main() {// 将不同级别目录名拼接成文件的完整路径p := filepath.Join("dir1", "dir2", "filename")fmt.Println("p:", p)fmt.Println(filepath.Join("dir1//", "filename"))fmt.Println(filepath.Join("dir1/../dir1", "filename"))// 从完整路径获取目录名和文件名fmt.Println("Dir(p):", filepath.Dir(p))fmt.Println("Base(p):", filepath.Base(p))// 是否是绝对路径fmt.Println(filepath.IsAbs("dir/file"))fmt.Println(filepath.IsAbs("/dir/file"))filename := "config.json"// 获取文件扩展名ext := filepath.Ext(filename)fmt.Println(ext)// 获取去除扩展名后的文件名fmt.Println(strings.TrimSuffix(filename, ext))// 获取两个路径之间的相对路径rel, err := filepath.Rel("a/b", "a/b/t/file")if err != nil {panic(err)}fmt.Println(rel)rel, err = filepath.Rel("a/b", "a/c/t/file")if err != nil {panic(err)}fmt.Println(rel)
}
$ go run file-paths.go
p: dir1/dir2/filename
dir1/filename
dir1/filename
Dir(p): dir1/dir2
Base(p): filename
false
true
.json
config
t/file
../c/t/file

66. Directories

下面例子展示了对目录的相关操作。

package mainimport ("fmt""os""path/filepath"
)func check(e error) {if e != nil {panic(e)}
}func main() {// 使用指定的名字和权限创建目录err := os.Mkdir("subdir", 0755)check(err)// 递归删除目录,等效于rm -rfdefer os.RemoveAll("subdir")createEmptyFile := func(name string) {d := []byte("")// 通过写空数据创建文件,文件不存在就创建check(os.WriteFile(name, d, 0644))}createEmptyFile("subdir/file1")// 强制创建目录,若路径上的父级不存在则创建,等效于mkdir -perr = os.MkdirAll("subdir/parent/child", 0755)check(err)createEmptyFile("subdir/parent/file2")createEmptyFile("subdir/parent/file3")createEmptyFile("subdir/parent/child/file4")// 列出指定目录下一级的所有目录和文件c, err := os.ReadDir("subdir/parent")check(err)fmt.Println("Listing subdir/parent")for _, entry := range c {fmt.Println(" ", entry.Name(), entry.IsDir())}// 改变当前目录,等效于Linux下的cd命令err = os.Chdir("subdir/parent/child")check(err)// 对当前目录执行ReadDirc, err = os.ReadDir(".")check(err)fmt.Println("Listing subdir/parent/child")for _, entry := range c {fmt.Println(" ", entry.Name(), entry.IsDir())}err = os.Chdir("../../..")check(err)fmt.Println("Visiting subdir")// 递归遍历指定目录下的所有子目录和文件,方式为深度优先遍历err = filepath.Walk("subdir", visit)
}func visit(p string, info os.FileInfo, err error) error {if err != nil {return err}fmt.Println(" ", p, info.IsDir())return nil
}
$ go run directories.go
Listing subdir/parentchild truefile2 falsefile3 false
Listing subdir/parent/childfile4 false
Visiting subdirsubdir truesubdir/file1 falsesubdir/parent truesubdir/parent/child truesubdir/parent/child/file4 falsesubdir/parent/file2 falsesubdir/parent/file3 false

67. Temporary Files and Directories

下面例子展示了对临时文件和目录的操作。

package mainimport ("fmt""os""path/filepath"
)func check(e error) {if e != nil {panic(e)}
}func main() {f, err := os.CreateTemp("", "sample")check(err)fmt.Println("Temp file name:", f.Name())// 操作系统会在程序结束后一段时间自动清理临时文件,不过最好还是自己做清理defer os.Remove(f.Name())_, err = f.Write([]byte{1, 2, 3, 4})check(err)dname, err := os.MkdirTemp("", "sampledir")check(err)fmt.Println("Temp dir name:", dname)defer os.RemoveAll(dname)fname := filepath.Join(dname, "file1")err = os.WriteFile(fname, []byte{1, 2}, 0666)check(err)
}
$ go run temporary-files-and-directories.go
Temp file name: /tmp/sample610887201
Temp dir name: /tmp/sampledir898854668

68. Embed Directive

embed编译指令可以在程序运行时从指定的文件获取数据到程序变量。这种编程风格有点类似于Srping中的依赖注入。

package mainimport ("embed"
)// 使用//go:embed指定从文件读取内容到变量fileString、fileByte
//go:embed folder/single_file.txt
var fileString string//go:embed folder/single_file.txt
var fileByte []byte// 使用//go:embed也可以打包多个文件到embed.FS类型变量,方便后续操作 
//go:embed folder/single_file.txt
//go:embed folder/*.hash
var folder embed.FSfunc main() {print(fileString)print(string(fileByte))content1, _ := folder.ReadFile("folder/file1.hash")print(string(content1))content2, _ := folder.ReadFile("folder/file2.hash")print(string(content2))
}
$ mkdir -p folder
$ echo "hello go" > folder/single_file.txt
$ echo "123" > folder/file1.hash
$ echo "456" > folder/file2.hash$ go run embed-directive.go
hello go
hello go
123
456

69. Testing and Benchmarking

Go对于单元测试和基准测试提供了原生的支持。仅需以指定的格式命名函数,通过正则匹配会被自动识别为单元测试或基准测试用例,再用go test命令启动测试。

package mainimport ("fmt""testing"
)func IntMin(a, b int) int {if a < b {return a}return b
}// 测试用例需要以Test开头
func TestIntMinBasic(t *testing.T) {ans := IntMin(2, -2)if ans != -2 {t.Errorf("IntMin(2, -2) = %d; want -2", ans)}
}func TestIntMinTableDriven(t *testing.T) {var tests = []struct {a, b intwant int}{{0, 1, 0},{1, 0, 0},{2, -2, -2},{0, -1, -1},{-1, 0, -1},}for _, tt := range tests {testname := fmt.Sprintf("%d,%d", tt.a, tt.b)// 用Run启动子测试用例,每个用例用数据表中获取输入t.Run(testname, func(t *testing.T) {ans := IntMin(tt.a, tt.b)if ans != tt.want {t.Errorf("got %d, want %d", ans, tt.want)}})}
}// 基准测试需要以Benchmark开头
func BenchmarkIntMin(b *testing.B) {// b.N是执行次数,由底层自动决定,以产生稳定精确的性能统计for i := 0; i < b.N; i++ {IntMin(1, 2)}
}
// 执行所有测试,显示详细信息,包括子测试
$ go test -v
== RUN   TestIntMinBasic
--- PASS: TestIntMinBasic (0.00s)
=== RUN   TestIntMinTableDriven
=== RUN   TestIntMinTableDriven/0,1
=== RUN   TestIntMinTableDriven/1,0
=== RUN   TestIntMinTableDriven/2,-2
=== RUN   TestIntMinTableDriven/0,-1
=== RUN   TestIntMinTableDriven/-1,0
--- PASS: TestIntMinTableDriven (0.00s)--- PASS: TestIntMinTableDriven/0,1 (0.00s)--- PASS: TestIntMinTableDriven/1,0 (0.00s)--- PASS: TestIntMinTableDriven/2,-2 (0.00s)--- PASS: TestIntMinTableDriven/0,-1 (0.00s)--- PASS: TestIntMinTableDriven/-1,0 (0.00s)
PASS
ok      examples/testing-and-benchmarking    0.023s// 执行基准测试
$ go test -bench=.
goos: darwin
goarch: arm64
pkg: examples/testing
BenchmarkIntMin-8 1000000000 0.3136 ns/op
PASS
ok      examples/testing-and-benchmarking    0.351s

70. Command-Line Arguments

通过Go提供的命令行api,可以方便地把Go编译出来的程序用作命令行工具。下面例子展示了Go程序读取命令行参数并处理的过程。

package mainimport ("fmt""os"
)func main() {// os.Args包含所有参数,当前文件编译生成的可执行文件为第一个参数argsWithProg := os.ArgsargsWithoutProg := os.Args[1:]arg := os.Args[3]fmt.Println(argsWithProg)fmt.Println(argsWithoutProg)fmt.Println(arg)
}
$ go build command-line-arguments.go
$ ./command-line-arguments a b c d
[./command-line-arguments a b c d]       
[a b c d]
c

71. Command-Line Flags

Go支持命令行标志,为命令行提供了不同的选项。例如grep -c中的-c就是一种命令行标志。

package mainimport ("flag""fmt"
)func main() {// 新定义word作为命令行标志,三个参数为:标志名、默认值、注释wordPtr := flag.String("word", "foo", "a string")numbPtr := flag.Int("numb", 42, "an int")forkPtr := flag.Bool("fork", false, "a bool")var svar stringflag.StringVar(&svar, "svar", "bar", "a string var")flag.Parse()fmt.Println("word:", *wordPtr)fmt.Println("numb:", *numbPtr)fmt.Println("fork:", *forkPtr)fmt.Println("svar:", svar)fmt.Println("tail:", flag.Args())
}
 go build command-line-flags.go$ ./command-line-flags -word=opt -numb=7 -fork -svar=flag
word: opt
numb: 7
fork: true
svar: flag
tail: []$ ./command-line-flags -word=opt
word: opt
numb: 42
fork: false
svar: bar
tail: []$ ./command-line-flags -word=opt a1 a2 a3
word: opt
...
tail: [a1 a2 a3]$ ./command-line-flags -word=opt a1 a2 a3 -numb=7
word: opt
numb: 42
fork: false
svar: bar
tail: [a1 a2 a3 -numb=7]$ ./command-line-flags -h
Usage of ./command-line-flags:-fork=false: a bool-numb=42: an int-svar="bar": a string var-word="foo": a string$ ./command-line-flags -wat
flag provided but not defined: -wat
Usage of ./command-line-flags:
...

72. Command-Line Subcommands

Go支持命令行子命令。例如go build和run就是go下面的两个子命令。

package mainimport ("flag""fmt""os"
)func main() {fooCmd := flag.NewFlagSet("foo", flag.ExitOnError)fooEnable := fooCmd.Bool("enable", false, "enable")fooName := fooCmd.String("name", "", "name")barCmd := flag.NewFlagSet("bar", flag.ExitOnError)barLevel := barCmd.Int("level", 0, "level")if len(os.Args) < 2 {fmt.Println("expected 'foo' or 'bar' subcommands")os.Exit(1)}switch os.Args[1] {case "foo":fooCmd.Parse(os.Args[2:])fmt.Println("subcommand 'foo'")fmt.Println("  enable:", *fooEnable)fmt.Println("  name:", *fooName)fmt.Println("  tail:", fooCmd.Args())case "bar":barCmd.Parse(os.Args[2:])fmt.Println("subcommand 'bar'")fmt.Println("  level:", *barLevel)fmt.Println("  tail:", barCmd.Args())default:fmt.Println("expected 'foo' or 'bar' subcommands")os.Exit(1)}
}
$ go build command-line-subcommands.go $ ./command-line-subcommands foo -enable -name=joe a1 a2
subcommand 'foo'enable: truename: joetail: [a1 a2]$ ./command-line-subcommands bar -level 8 a1
subcommand 'bar'level: 8tail: [a1]$ ./command-line-subcommands bar -enable a1
flag provided but not defined: -enable
Usage of bar:-level intlevel

73. Environment Variables

下面例子展示了环境变量的设置和读取。

package mainimport ("fmt""os""strings"
)func main() {// 环境变量为进程级别,进程退出后设置的变量消失os.Setenv("FOO", "1")fmt.Println("FOO:", os.Getenv("FOO"))fmt.Println("BAR:", os.Getenv("BAR"))fmt.Println()// 读取到的变量列表与具体机器有关for _, e := range os.Environ() {pair := strings.SplitN(e, "=", 2)fmt.Println(pair[0])}
}
$ go run environment-variables.go
FOO: 1
BAR: TERM_PROGRAM
PATH
SHELL
...
FOO$ BAR=2 go run environment-variables.go
FOO: 1
BAR: 2
...

74. HTTP Client

Go提供了方便的Http请求和处理的工具。下面是HTTP客户端的例子。

package mainimport ("bufio""fmt""net/http"
)func main() {// 仅一句Get就能访问http urlresp, err := http.Get("https://gobyexample.com")if err != nil {panic(err)}defer resp.Body.Close()fmt.Println("Response status:", resp.Status)scanner := bufio.NewScanner(resp.Body)for i := 0; scanner.Scan() && i < 5; i++ {fmt.Println(scanner.Text())}if err := scanner.Err(); err != nil {panic(err)}
}
$ go run http-clients.go
Response status: 200 OK

Go by Example

75. HTTP Server

下面是HTTP服务端的例子。仅需HandleFunc和ListenAndServe两句代码就能实现一个简单的服务端,非常方便。

package mainimport ("fmt""net/http"
)func hello(w http.ResponseWriter, req *http.Request) {fmt.Fprintf(w, "hello\n")
}func headers(w http.ResponseWriter, req *http.Request) {for name, headers := range req.Header {for _, h := range headers {fmt.Fprintf(w, "%v: %v\n", name, h)}}
}func main() {http.HandleFunc("/hello", hello)http.HandleFunc("/headers", headers)http.ListenAndServe(":8090", nil)
}
 	$ go run http-servers.go &$ curl localhost:8090/hello
hello

76. Context

下面例子展示了通过HTTP请求上下文处理请求取消的操作。

package mainimport ("fmt""net/http""time"
)func hello(w http.ResponseWriter, req *http.Request) {ctx := req.Context()fmt.Println("server: hello handler started")defer fmt.Println("server: hello handler ended")select {case <-time.After(10 * time.Second):fmt.Fprintf(w, "hello\n")// 若在10秒内断开请求连接,则执行下面逻辑case <-ctx.Done():err := ctx.Err()fmt.Println("server:", err)internalError := http.StatusInternalServerErrorhttp.Error(w, err.Error(), internalError)}
}func main() {http.HandleFunc("/hello", hello)http.ListenAndServe(":8090", nil)
}
$ go run context-in-http-servers.go &$ curl localhost:8090/hello
server: hello handler started
// 这里模拟在接到回应前,断开请求连接
^C
server: context canceled
server: hello handler ended

77. Spawning Processes

下面例子展示了在Go程序中调用其他命令,如date,并获取返回值。

package mainimport ("fmt""io""os/exec"
)func main() {dateCmd := exec.Command("date")dateOut, err := dateCmd.Output()if err != nil {panic(err)}fmt.Println("> date")fmt.Println(string(dateOut))_, err = exec.Command("date", "-x").Output()if err != nil {switch e := err.(type) {case *exec.Error:fmt.Println("failed executing:", err)case *exec.ExitError:fmt.Println("command exit rc =", e.ExitCode())default:panic(err)}}grepCmd := exec.Command("grep", "hello")grepIn, _ := grepCmd.StdinPipe()grepOut, _ := grepCmd.StdoutPipe()grepCmd.Start()grepIn.Write([]byte("hello grep\ngoodbye grep"))grepIn.Close()grepBytes, _ := io.ReadAll(grepOut)grepCmd.Wait()fmt.Println("> grep hello")fmt.Println(string(grepBytes))lsCmd := exec.Command("bash", "-c", "ls -a -l -h")lsOut, err := lsCmd.Output()if err != nil {panic(err)}fmt.Println("> ls -a -l -h")fmt.Println(string(lsOut))
}
$ go run spawning-processes.go 
> date
Thu 05 May 2022 10:10:12 PM PDTcommand exited with rc = 1
> grep hello
hello grep> ls -a -l -h
drwxr-xr-x  4 mark 136B Oct 3 16:29 .
drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
-rw-r--r--  1 mark 1.3K Oct 3 16:28 spawning-processes.go

78. Exec’ing Processes

下面展示了从Go程序启动一个新的进程。与上一个例子不同,这里启动新进程后,原Go程序会主动退出。

package mainimport ("os""os/exec""syscall"
)func main() {binary, lookErr := exec.LookPath("ls")if lookErr != nil {panic(lookErr)}args := []string{"ls", "-a", "-l", "-h"}env := os.Environ()execErr := syscall.Exec(binary, args, env)if execErr != nil {panic(execErr)}
}
$ go run execing-processes.go
total 16
drwxr-xr-x  4 mark 136B Oct 3 16:29 .
drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
-rw-r--r--  1 mark 1.3K Oct 3 16:28 execing-processes.go

79. Signals

下面例子展示了信号量的使用。通过监听中止信号量,在外部强行中断程序后,还能执行一段结束代码。

package mainimport ("fmt""os""os/signal""syscall"
)func main() {sigs := make(chan os.Signal, 1)// 监听程序中止的信号量,并存入通道sigssignal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)done := make(chan bool, 1)go func() {// 从sigs通道读取信号量并打印sig := <-sigsfmt.Println()fmt.Println(sig)done <- true}()fmt.Println("awaiting signal")<-donefmt.Println("exiting")
}
$ go run signals.go
awaiting signal
^C
interrupt
exiting

80. Exit

下面例子展示了以指定退出码主动退出进程。主动退出时不会指定defer语句。

package mainimport ("fmt""os"
)func main() {defer fmt.Println("!")os.Exit(3)
}
$ go run exit.go
exit status 3$ go build exit.go
$ ./exit
$ echo $?
3

相关内容

热门资讯

想找个中立的人太难:马斯克推特... IT之家 2 月 26 日消息,很少有高管能像埃隆 · 马斯克那样招致如此多的争议,这位特斯拉掌门人...
京东、中兴、大疆等19家企业总... 深圳商报·读创客户端记者曹欣 新春伊始,深圳湾超级总部基地(以下简称 “深超总”)建设全面提速,京东...
压岁钱遇上理财,有儿童专属储蓄... 作者:张昕迎 编辑:周梦梅 编者按:拼车返乡、拼单买年货,今年过年,你“拼”了吗?当Z世代主导春节,...
高盛谈AI交易:“AI基建”的... 当AI资本开支越冲越猛、估值越来越贵时,高盛提醒市场:真正的风险,往往出现在“增速开始放慢”的那一刻...
楼市新信号,二手房业主不愿卖房... 作者:千寻 01 2026开年以来,全国的二手房市场出现了新变化,二手房业主们不愿意继续割肉卖房了。...
原创 券... 券商拉盘指数走强!盘面暗藏背离,老股民直呼心慌 炒股的人都懂,A股最让人琢磨不透的,不是单边下跌,而...
又一家居企业冲击港股上市,20... 群核科技向港交所主板递交上市申请,摩根大通和建银国际担任联席保荐人。 最新数据显示,2025年,公司...
中国铁建重工集团股份有限公司2... 本公司董事会及全体董事保证本公告内容不存在任何虚假记载、误导性陈述或者重大遗漏,并对其内容的真实性、...
原创 松... 时光倒流至上世纪九十年代,那是日本电池工业的辉煌岁月。 1991年,索尼发布了人类历史上第一款商用锂...
自变量机器人一个月内又完成数亿... 投资界2月26日消息,据企查查,自变量机器人(X Square Robot)完成数亿元新一轮融资,本...
原创 2... 内容提要 2026年1月,货币市场日均交易量及余额均增加,主要回购利率走势分化,大型商业银行日均净融...
电池概念股走低,多只电池相关E... 电池概念股走低,阳光电源、宁德时代、亿纬锂能跌超4%。 受盘面影响,多只电池相关ETF跌超2%。 ...
构建“国际化、法治化、市场化”... 在当前全球科技竞争日益激烈的背景下,炒菜机器人行业作为新兴领域正展现出巨大的发展潜力。以东莞市山智智...
环渤海动力煤价格指数685元/... 上证报中国证券网讯(记者 王文嫣)2月25日,秦皇岛煤炭网发布最新一期环渤海动力煤价格指数,本报告期...
STARTRADER:摩根大通... 2月25日,摩根大通发布最新贵金属展望报告,宣布将黄金长期价格预期上调至4500美元/盎司,同时重申...
鼎泰高科晋级10倍股 人民财讯2月25日电,2月25日,鼎泰高科(301377)午后股价大涨,盘中一度涨超15%,收盘涨幅...
恒丰银行股权0.7元无人接盘,... 【文/羽扇观金工作室】 3月7日,一笔挂牌起拍价2660万元,3800万股的恒丰银行股权将在阿里资...
中国将印度告上WTO 文︱陆弃 从瑞士日内瓦那幢灰色会议楼里传出的消息,往往代表着一种秩序在悄然发生断裂。2月24日,世界...