Java 转 go 学习 - 基本语法

文章目录

  • [1. 包管理](#1. 包管理)
    • [1.1 基本概念](#1.1 基本概念)
    • [1.2 包导入方法](#1.2 包导入方法)
    • [1.3 可见性](#1.3 可见性)
    • [1.4 Go 项目结构](#1.4 Go 项目结构)
  • [2. 注释](#2. 注释)
  • [3. 函数](#3. 函数)
  • [4. 类型](#4. 类型)
    • [4.1 基本类型](#4.1 基本类型)
      • [4.1.1 数值类型(精准位数划分)](#4.1.1 数值类型(精准位数划分))
      • [4.2.2 布尔类型](#4.2.2 布尔类型)
      • [4.2.3 字符串类型](#4.2.3 字符串类型)
    • [4.2 复合类型](#4.2 复合类型)
      • [4.2.1 数组](#4.2.1 数组)
      • [4.2.2 切片](#4.2.2 切片)
      • [4.2.3 map](#4.2.3 map)
      • [4.2.4 结构体](#4.2.4 结构体)
      • [4.2.5 通道](#4.2.5 通道)
    • [4.3 特殊类型](#4.3 特殊类型)
      • [4.3.1 指针类型](#4.3.1 指针类型)
      • [4.3.2 接口](#4.3.2 接口)
      • [4.3.3 函数类型](#4.3.3 函数类型)
      • [4.3.4 error 类型](#4.3.4 error 类型)
    • [4.4 自定义类型](#4.4 自定义类型)
  • [5. 小结](#5. 小结)

本系列文章:


1. 包管理

1.1 基本概念

Go 中 包(Package) 是代码的最小结构化单元,等价于 Java 的 Package,每个 .go 文件都属于一个包,文件的第一行就要写明 package ... 来表明当前文件属于哪个包。

包类型有两种:

  • main :可以执行的程序入口,每一个应用程序都要有一个 main 包,包含 main 函数,编译之后可以生成可执行文件,类比 Java 就是 main 方法。
  • 普通包(工具包) :比如 fmt、net/http 等,这些文件没有 main 方法,编译之后生成 .a 静态库,不能直接执行,类似 Java 的 util.

一般来说包名和目录名是一样的,也可以不一样,但是为了提高可读性最好一样,同一个目录下面的所有 .go 文件都 必须属于一个包。

Go 标准库就提供了一些可以直接用的包,比如经典的 fmt、net/http,就放在 $GOROOT/src 下,下面是本地的截图,可以通过 go env GOROOT 来查看 GOROOT 路径:

1.2 包导入方法

  • 标准导入(最常用) :import "包路径",比如 import "fmt"。

  • 别名导入 :import f "fmt",意思是导入 fmt 用 f 来代替,避免命名冲突。

  • 点导入 :import . "fmt",直接调用函数,无需包名.

  • 空白导入 :import _ "github.com/go-sql-driver/mysql",用来初始化包,不直接使用其导出函数,用于注册驱动.

  • 批量导入 :用 () 批量包裹导入语句(规范写法)

1.3 可见性

Go 没有 public/private/protected/default 这几个关键字,就靠首字母大小写来控制可见性:

标识符首字母 可见性 作用范围 Java 类比
大写 (如 GetHello、fmt.Println) 导出(公开) 可被其他包导入后访问 public
小写 (如 getHello) 未导出(私有) 仅当前包内可访问 private(同包)

举个例子:

pkg 包下的 main.go 如果要调用 cmd 包下面的 app.go 和 util.go 的方法,比如右边 GetHello2 就是 app.go 里面的方法,这种情况下需要将方法首字母大写,如果改成小写就会报错找不到定义的方法,因为此时的方法是包私有的,也就是只有 cmd 包下面的 go 文件可以调用这个方法。

下面就是在 util.go 中调用这个小写方法,可以看到是没有问题的。

1.4 Go 项目结构

下面是推荐的 Go 项目结构:

go 复制代码
项目名/
├── go.mod                  # 模块声明
├── go.sum                  # 依赖哈希
├── main.go                 # 项目入口(package main,含 main())
├── cmd/                    # 多可执行程序入口(可选)
│   └── app/                # 另一个可执行程序
│       └── main.go
├── pkg/                    # 公共工具包(被多个模块引用)
│   └── calc/               # 包名calc,放工具函数
│       ├── add.go
│       └── sub.go
└── internal/               # 内部包(仅当前项目可导入,外部不可)
    └── utils/
        └── log.go

2. 注释

跟 Java 差不多,Go 的注释是下面两种,就不多说了:

  • //,单行注释
  • /**/,多行注释

3. 函数

这里先对函数做一个简单的介绍,跟 java 一样,main 函数是一个可执行程序的入口,但是如果存在 init 方法,会先执行 init 方法,再执行 main 方法,如下面的例子(上一篇文章的初始化项目):

go 复制代码
package main

import (
	"fmt"
	"go-learn-1/learn-1/pkg/cmd"
)

func init() {
	fmt.Println("init")
}

func main() {
	fmt.Println(cmd.GetHello1())
	fmt.Println(cmd.GetHello2())
}

输出结果如下:

go 复制代码
init
✅ Running as [pkg]: learn-1/pkg/cmd/util.go
✅ Running as [pkg]: learn-1/pkg/cmd/app.go

函数最简单的格式就是 func functionName(),() 中可以通过 , 传入参数,也可以在 () 后面定义返回的类型,但是注意,go 的返回值可以写多个,这个跟 Java 语法有点不一样,我们定义一个 math.go,里面包含一个 caculate 方法用于计算 +、-、*、/:

go 复制代码
package cmd

func Caculate(a int, b int) (int, int, int, int) {
	return a + b, a - b, a * b, a / b
}

在 main 方法中进行调用

go 复制代码
package main

import (
	"fmt"
	"go-learn-1/learn-1/pkg/cmd"
)

func main() {
	fmt.Println(cmd.Caculate(12, 3))
}

输出结果如下:

go 复制代码
15 9 36 4

4. 类型

首先来看下类型总览:

类型大类 具体类型 Java 类比 核心特点
基础类型 整数、浮点、布尔、字符串、复数 基本类型(int/boolean/String) 均为值类型,无包装类
复合类型 数组、切片(slice)、映射(map)、结构体(struct)、通道(channel) 数组、ArrayList、HashMap、类、无对应 组合多值,slice/map/channel 是引用类型
特殊类型 指针、接口、函数类型、error 类型 指针、接口、Lambda、Exception Go 特有 / 差异大,实战高频
自定义类型 type 关键字定义的新类型(如 type MyInt int) 自定义类 / 枚举 类型隔离,可绑定方法

核心规则:Go 是静态类型语言(编译期确定类型)、强类型语言(无隐式类型转换,如 int 不能直接转 string)

4.1 基本类型

基本类型就是 Go 最底层的类型,全部是值类型,也就是方法传参的时候通过值传递,我们都知道 Java 方法传参的时候可以通过值传递 或者是引用传递 ,如果是对象传递的就是对象的引用,如果是基本数据类型就传的是值,同时 go 是没有包装类的。

4.1.1 数值类型(精准位数划分)

类型 说明 示例 Java 类比
int8/16/32/64 有符号整数(8-64 位) var a int32 = 10 byte/short/int/long
uint8/16/32/64 无符号整数(8-64 位) var b uint8 = 255 无直接对应(需手动处理)
int/uint 与平台位数一致(32/64 位) var c int = 100 int/long
float32/64 浮点数 var d float64 = 3.14 float/double
complex64/128 复数(极少用) var e complex64 = 1+2i 无直接对应
go 复制代码
func baseTest() {
	// 有符号整数
	var a int32 = 10
	fmt.Println("int32类型:", a)
	// 输出 int32类型: 10

	var b uint8 = 255
	// b = 256 报错, 常量256超出uint8类型范围
	fmt.Println("uint8类型:", b)
	// 输出 uint8类型: 255

	// 浮点型(优先用float64,精度更高)
	var pi float64 = 3.1415926
	fmt.Println("float64类型:", pi)
	// 输出 float64类型: 3.1415926
}

4.2.2 布尔类型

类型 说明 示例
bool 仅 true/false,不能用 0/1 替代 var isOk bool = true

对于 go,不能将 1 复制给 bool 类型.

go 复制代码
func boolTest() {
	var isSuccess bool = true
	var isFail bool = false
	fmt.Println("成功:", isSuccess)
	// 输出:成功: true
	fmt.Println("失败:", isFail)
	// 输出:失败: false

	// 错误示例:Go不支持0/1替代bool
	// var flag bool = 1 // 编译报错:无法将int类型赋值给bool类型
}

4.2.3 字符串类型

类型 说明 示例
string 不可变、UTF-8 编码(天然支持中文) var s string = "你好 Go"

下面是 string 的例子以及 string 比较常用的一些函数,💡 注意对于 go,中文的字节数是 3 字节。

go 复制代码
func stringTest() {
	// 天然支持中文(UTF-8编码)
	var s string = "你好 Go"
	fmt.Println("字符串内容:", s)
	// 输出:字符串内容: 你好 Go
	fmt.Println("字节数:", len(s))
	// 输出:字节数: 7

	// 字符串常用操作(strings包)
	fmt.Println("是否包含Go:", strings.Contains(s, "Go"))
	fmt.Println("替换:", strings.Replace(s, "Go", "Golang", 1)) // 输出:替换: 你好 Golang
}

4.2 复合类型

类型 定义示例 核心特点 Java 类比
数组 N T var arr 3int = 3int{1,2,3} 值类型、长度固定(3int 和 4int 是不同类型) 数组(但 Java 数组长度是属性)
切片 \[\] T slice := make(\[\]int, 3, 5) 引用类型、动态扩容、基于数组创建 ArrayList(更轻量,无额外方法)
映射 map K V m := make(mapstringint) m"age" = 20 引用类型、键需可比较、无序 HashMap
结构体 struct type User struct { Name string json:"name" Age int } 值类型、可绑定方法、支持标签 自定义类(无继承)
通道 chan T ch := make(chan int) 引用类型、并发安全、goroutine 通信 BlockingQueue(仅功能类比)

4.2.1 数组

下面简单测试下这几种类型,后面等到后续的章节再一个一个细看,数组的创建语法给 java 还是不一样的,不需要 new,数组的遍历语法和 java 不一样:

java 复制代码
func arrTest() {
	var arr [3]int = [3]int{1, 2, 3}
	fmt.Println("arr: ", arr)
	fmt.Println("arr len: ", len(arr))
	
	// 遍历数组
	for i, v := range arr {
		fmt.Printf("index: %d, value: %d\n", i, v)
	}
	
	// 输出结果
	// arr:  [1 2 3]
	// arr len:  3
	// index: 0, value: 1
	// index: 1, value: 2
	// index: 2, value: 3
}

4.2.2 切片

切片类型,切片类型类似 Java 的 ArrayList,基于数组来动态扩容,创建切片的方法有三种:

  1. 基于数组创建
  2. 直接使用 make 创建

💡 切片的获取元素方式和设置元素方式跟数组是一样的,同时这里的扩容不像 ArrayList 一样是扩容 1.5 倍。

go 复制代码
func sliceTest() {
	// 1. 基于数组来创建
	arr := [3]int{1, 2, 3}
	// 左闭右开: [1, 2]
	slice1 := arr[0:2]
	fmt.Println("slice1: ", slice1)
	fmt.Println("slice1: ", len(slice1))

	// 2. 使用 make 初始化
	// 长度为 3 的切片, 初始值: [0, 0, 0], 容量是 5
	slice2 := make([]int, 3, 5)
	slice2[0] = 100
	slice2[1] = 200
	slice2[2] = 300

	fmt.Println("slice2: ", slice2)
	fmt.Println("slice2: ", len(slice2))

	// 追加数据
	slice2 = append(slice2, 400, 500)
	fmt.Println("slice2: ", slice2)
	fmt.Println("slice2: ", len(slice2))

	// 继续追加, 动态扩容
	slice2 = append(slice2, 600, 700)
	fmt.Println("slice2: ", slice2)
	fmt.Println("slice2: ", len(slice2))
}

输出结果如下:

go 复制代码
slice1:  [1 2]
slice1:  2
slice2:  [100 200 300]
slice2:  3
slice2:  [100 200 300 400 500]
slice2:  5
slice2:  [100 200 300 400 500 600 700]
slice2:  7

4.2.3 map

下面就是用的比较多的 map 类型的创建,类比 Java 的 HashMap,map 的初始化有两种方式,可以通过 make 初始化,又或者通过字面量来初始化,获取值则是和数组方式差不多,只不过数组是传入下标获取值,而 map 则是传入 key 获取值,下面是简单的示例:

go 复制代码
func mapTest() {
	// 1. make 初始化
	// key: string
	// value: int
	m1 := make(map[string]int)

	m1["age"] = 20
	m1["score"] = 35
	fmt.Println("map: ", m1)

	// 2. 字面量初始化, 可以提前初始化一些值进去
	m2 := map[string]int{
		"age":   21,
		"score": 22,
	}
	fmt.Println("map: ", m2)

	// 获取值
	name1, ok := m1["age"]
	if ok {
		fmt.Println("age:", name1)
	}

	// 删除 key-value
	delete(m1, "age")
	fmt.Println("m1:", m1)

}

func main() {
	mapTest()
}

输出结果如下:

go 复制代码
map:  map[age:20 score:35]
map:  map[age:21 score:22]
age: 20
m1: map[score:35]

4.2.4 结构体

这部分就和 c 语言的语法差不多了,同样的 struct 就代表结构体的关键字,结构体可以类比 Java 的类,既然有类,那么同样类里面有方法,而我们直到 go 的结构体里面是不能定义方法的,但是 go 也可以用其他方式为结构体来绑定方法,例子如下:

go 复制代码
type User struct {
	Name      string `json:"name"` // json 序列化的字段名
	Age       int    `json:"age"`
	IsStudent bool   `json:"isStudent"`
}

// func 后面定义上结构体, 绑定方法
func (u User) GetInfo() string {
	return fmt.Sprintf("name: %s, age: %d, isStudent: %v", u.Name, u.Age, u.IsStudent)
}

func main() {
	// 初始化结构体
	u1 := User{Name: "张三", Age: 18, IsStudent: true}
	fmt.Println("结构体 u1 内容: ", u1)
	fmt.Println(u1.GetInfo())

	// 指针初始化, 避免复制大对象
	u2 := &User{Name: "李四", Age: 20, IsStudent: false}
	// 访问指针内容
	fmt.Println("结构体 u2 内容: ", *u2)
	fmt.Println(u2.GetInfo())
}

输出结果如下:

go 复制代码
结构体 u1 内容:  {张三 18 true}
name: 张三, age: 18, isStudent: true
结构体 u2 内容:  {李四 20 false}
name: 李四, age: 20, isStudent: false

4.2.5 通道

创建通道,然后往里面写入数据,最后可以遍历通道获取里面的数据,先进先出:

go 复制代码
func channelTest() {
	// 创建有缓冲通道(容量2)
	ch := make(chan int, 2)

	// 发送数据到通道(goroutine中执行)
	go func() {
		ch <- 10
		ch <- 20
		close(ch) // 关闭通道
	}()

	// 接收通道数据
	for num := range ch {
		fmt.Println("通道接收数据: ", num)
		// 10
		// 20
	}
}

4.3 特殊类型

类型 定义 / 示例 核心作用 Java 类比
指针 *T a := 10 p := &a // 取地址 *p = 20 // 解引用 指向内存地址,避免大对象复制 无显式指针(仅引用)
接口 interface type Greeting interface { SayHello() string } 行为抽象、隐式实现、空接口接收任意类型 接口(但 Go 无需 implements 关键字)
函数类型 type CalculateFunc func(int, int) int func Add(a,b int) int { return a+b } 函数是一等公民,可作为参数 / 返回值 Lambda / 函数式接口
error 类型 func Divide(a,b int) (int, error) { if b==0 { return 0, fmt.Errorf("除数为 0") } return a/b, nil } 错误处理核心,内置接口(仅 Error() 方法) Exception(无 try-catch,靠 if err!=nil 处理)

4.3.1 指针类型

指针类似 C 语言的指针,通过 & 取地址,然后通过 * 可以获取到地址里面的内容,下面是一个简单的例子,指针可以和基本数据类型、函数等等相结合,这里就先简单看下基本数据类型的例子:

go 复制代码
func pointerTest() {
	a := 10
	p := &a // 取a的内存地址,p是 *int 类型
	fmt.Println("a 的地址: ", p)
	//
	fmt.Println("a 的值", *p)

	// 通过指针修改原变量值
	*p = 20
	fmt.Println(a)
}

输出如下:

go 复制代码
a 的地址:  0xc00000a088
a 的值 10
20

4.3.2 接口

Go 的接口和 Java 的设计理念不同,Go 属于隐式实现,而 Java 属于显式实现,对于 Go,只要结构体实现了接口的所有方法,就自动满足接口,而对于 Java,必须明确声明 class X implements Interface。

⚠️ 有一点比较特殊的就是 Java 里面有 Object,而 Go 里面也有空接口,空接口可以赋值任何类型,通常作为顶层的实现,下面看一个简单的例子:

go 复制代码
// 定义接口
type Getting interface {
	SayHello() string
}

// 定义结构体, 类比 Java 的类, 实现接口
type Student struct {
	Name string
}

type Teacher struct {
	Name string
}

// 实现了 SayHello 接口
func (s Student) SayHello() string {
	return "hello, " + s.Name
}

// 实现了 SayHello 接口
func (t Teacher) SayHello() string {
	return "hello, " + t.Name
}

// 传入接口
func Greet(g Getting) string {
	return "Greet: " + g.SayHello()
}

// 特殊: 空接口, 类比 Java 的 Object
func LogData(data interface{}) {
	// 这里可以处理任何传入的数据
	fmt.Printf("记录日志: %v\n", data)
}

func interfaceTest() {
	stu := Student{
		Name: "student",
	}
	fmt.Println(stu.SayHello())
	tea := Teacher{
		Name: "teacher",
	}
	fmt.Println(tea.SayHello())

	fmt.Println(Greet(stu))
	fmt.Println(Greet(tea))

	LogData(1)
	LogData("123")
	LogData(stu)
}

func main() {
	interfaceTest()
	// hello, student
	// hello, teacher
	// Greet: hello, student
	// Greet: hello, teacher
	// 记录日志: 1
	// 记录日志: 123
	// 记录日志: {student}
}

Getting 就是接口名称,而结构体 Student 和 Teacher 实现了这个接口,Greet 方法需要传入接口,返回字符串,LogData 里面传入一个空接口,负责打印日志。

4.3.3 函数类型

函数类型和接口差不多,类似 Java 的函数式编程,举个例子:type Handler func(w http.ResponseWriter, r *http.Request),通过 func 来定义一个函数类型:

  • ✅ 接口是不需要显示声明的,如果一个结构体实现了接口中定义的所有方法,它就自动实现了该接口。
  • ✅ 函数类型本身就是一个类型,任何签名匹配的 函数 、方法 或 匿名函数(闭包) 都可以赋值给该类型的变量。

下面是函数类型的简单例子:

go 复制代码
type ProcessFunc func(string) string

// 具体逻辑函数, 参数和返回值跟上面的 ProcessFunc 一样, 所以可以将 toUpper 赋值到 ProcessFunc
func toUpper(data string) string {
	return strings.ToUpper(data)
}

// 具体使用
func Run(p ProcessFunc, s string) {
	res := p(s)
	fmt.Println(res)
}

func funcTest() {
	// 直接调用函数
	Run(toUpper, "hello")
	// 传入匿名函数
	Run(func(s string) string { return strings.ToLower(s) }, "HELLO")
}

func main() {
	funcTest()
}

ProcessFunc 是定义的函数,传入一个 string 字符串,最终返回结果是 string 类型的字符串,Run 方法接受 ProcessFunc 类型的传参,在方法内部调用具体逻辑,toUpper 的传参和返回值和 ProcessFunc 一样,所以可以作为这个函数的参数,又或者像是第二种写法一样,直接传入匿名函数,匿名函数的参数和返回值要和定义的函数一致。

这种写法比 Java 方便,Java 中如果需要传入一个函数,就需要用到 Java8 的函数式编程,使用 Function 这些对象进行传参,而 go 则是可以直接把函数进行传递,如果只需要传递一段单一的逻辑,或者作为回调函数(Callback) ,这种情况下可以考虑函数式编程。

4.3.4 error 类型

go 内置包 builtin 中提供了 error 的相关定义,error 是一个接口,代码如下:

go 复制代码
type error interface {
    Error() string
}

也就是说所有实现了 Error() string 方法的类型都自动实现了 error 接口,可以作为错误使用,当然我们也可以直接使用 error 作为返回值,下面就来看下两种方式,分别是标准的错误返回以及我们自定义一个 error 类型。

go 复制代码
// 1. 标准错误
func doErrorSimple() error {
	return errors.New("something went wrong")
}

// 2. 自定义错误
type MyCustomError struct {
	Code    int
	Message string
}

// 结构体实现 error 接口
func (e MyCustomError) Error() string {
	return fmt.Sprintf("[Error Code %d]: %s", e.Code, e.Message)
}

// 返回自定义结构体
func doComplexThing() error {
	return MyCustomError{Code: 500, Message: "something went wrong"}
}

func errorTest() {
	if err := doErrorSimple(); err != nil {
		fmt.Println("SimpleError: ", err)
	}

	// 获取自定义异常
	if err := doComplexThing(); err != nil {
		fmt.Println("ComplexThingError: ", err)

		if customErr, ok := err.(MyCustomError); ok {
			fmt.Println(customErr.Code, customErr.Message)
		}
	}

	// 写法二, 指针写法
	if err := doComplexThing(); err != nil {
		fmt.Println("ComplexThingError: ", err)

		var customErr MyCustomError
		if errors.As(err, &customErr) {
			fmt.Println(customErr.Code, customErr.Message)
		}
	}
}

func main() {
	errorTest()
}

输出结果如下:

go 复制代码
SimpleError:  something went wrong
ComplexThingError:  [Error Code 500]: something went wrong
500 something went wrong
ComplexThingError:  [Error Code 500]: something went wrong
500 something went wrong

📌 在 Go 中,nil 表示 "没有错误",这是 Go 错误处理模式的基础:函数通常返回最后一个参数为 error,开发者需要检查是否为 nil,如果不为 nil 就说明没有发生错误,再继续执行下面的逻辑。

Go 提供了下面两个主要函数来创建 error:

函数 包 用途 示例
errors.New errors 创建静态文本错误 errors.New("file not found")
fmt.Errorf fmt 创建格式化文本错误(支持 %v, %w 等) fmt.Errorf("user %s not found", name)

同时 Go 1.13+ 之后可以通过 %w 来包装 error,能够保留原始的错误消息,同时添加新的上下文,并且可以通过 errors.Is 和 errors.As 来检查底层错误。

go 复制代码
func main() {
	err := fmt.Errorf("failed to open file: %w", os.ErrNotExist)

	// 检查是否包含底层错误
	if errors.Is(err, os.ErrNotExist) {
		fmt.Println(err)
		fmt.Println("文件确实不存在")
		// failed to open file: file does not exist
		// 文件确实不存在
	}
}

📚 Go 中没有 try-catch 这种语法,必须手动检查每个返回的 err 是否为 nil。

4.4 自定义类型

类型 定义示例 核心特点
自定义类型 type MyInt int var a MyInt = 10 //a = 20 ❌ 类型不匹配 全新类型,与原类型隔离,需显式转换
类型别名 type IntAlias = int var c IntAlias = 30 c = 40 ✅ 仅别名,与原类型等价,无需转换

我们可以通过 type {typeName} {type} 来自定义类型,同时也可以为类型设置别名,来看下简单的例子:

go 复制代码
package main

import "fmt"

// 自定义类型(全新类型)
type MyInt int

// 类型别名(仅别名)
type IntAlias = int

func main() {
	// 自定义类型
	var a MyInt = 10
	var b int = 20
	// a = b // 编译报错: 无法将int类型赋值给MyInt类型\	
	//显式转换后可赋值
	a = MyInt(b)             
	// 自定义类型: 20
	fmt.Println("自定义类型:", a)

	// 类型别名
	var c IntAlias = 30
	var d int = 40
	// 无需转换,直接赋值
	c = d                   
	fmt.Println("类型别名:", c)
	// 类型别名: 40
}

5. 小结

这篇文章就简单看下 go 的基本语法,下一篇文章继续学习 go 的类型转换以及常用的数组,结构体...等类型的操作。

如有错误,欢迎指出!!!

相关推荐
让头发掉下来2 小时前
Kettle学习-17作业的创建与定时调度
学习
小刘在重生~3 小时前
CSS 零基础完整学习笔记|选择器|盒子模型|布局
css·笔记·学习
AOI小白新手上路3 小时前
韦东山《ARM 架构与编程》3-3 IMX6ULL 的 GPIO 操作方法 · 学习笔记
arm开发·学习·架构
浩瀚地学3 小时前
deepagents学习打卡day07
经验分享·笔记·python·学习·agent
Awh-3 小时前
ARM 裸机开发 DAY5 学习笔记
arm开发·笔记·学习
李游Leo4 小时前
HarmonyOS 7 + ArkUI + Adaptive Layout 学习笔记:折叠屏多形态布局适配与窗口状态响应机制【鸿蒙心迹】
笔记·学习·harmonyos
kyrie_sakura4 小时前
大模型学习6 -- 深度学习 1 概述和PyTorch
pytorch·深度学习·学习
传奇开心果编程4 小时前
【Flutter入门练中学】第3课:滚动与列表
android·学习·flutter·ui·ios
李游Leo5 小时前
HarmonyOS 7 + ArkTS + Image Kit 学习笔记:图像超分处理链路与 PixelMap 数据流实践【鸿蒙心迹】
笔记·学习·harmonyos