Golang学习笔记(二)

目录

1 regexp内置包

2 指针

2.1 声明指针

 2.2 函数传递指针

3 结构体

3.1 结构体声明

3.2 结构体指针

3.3 匿名字段

3.4 结构体替代类

3.5 组合取代继承

4 方法

5 接口

5.1 声明接口

5.2 空接口

5.3 类型断言与类型选择

5.4 指针接收实现接口

5.5 接口嵌套

5.6 多态

6 并发

6.1 协程

6.2 信道

6.3 缓冲信道

 6.4 WaitGroup

6.5  select

6.6 Mutex 

7 异常处理

7.1 error接口

7.2 panic和recover

1)panic

8 其他

8.1 反射

8.2 文件操作

1)fileinfo

 2)filepath

3)创建

4)文件读写

结构体:type Employee struct { }
函    数:func functionname(parametername type) returntype {  }
方    法:func (t Type) methodName(parameter list) { }
接    口:type VowelsFinder interface {  FindVowels() []rune }

1 regexp内置包

正则表达式(regular expression)就是由元字符组成的一种字符串匹配的模式,使用这种模式可以实现对文本内容解析、校验、替换。

 1)检查正则表达式与字节数组是否匹配。

func Match(pattern string,b []byte)(method bool,err error)

flag,er = regexp.Match("[1-9]",[]byte("123456"))

2)检查正则表达式与字符串是否匹配。

func MatchString(pattern string,s string)(method bool,err error)
flag,_ := regexp.MatchString("[1-9]","123456")

3)将正则表达式字符串编译成正则表达式对象(Regexp)。

func Compile(expr string) (*regexp,error)
Myregexp,_ := regexp.Compile("[1-9]")

4)MustCompile()用法同Compile(),但是不返回error。如果表达式不能被解析就会panic。

func MustCompile(str string) *regexp
Myregexp:= regexp.MustCompile("[1-9]")

 5)判断Regexp正则对象是否与给定的字节数组匹配。

func (re *Request) Match(b []byte) bool
Myregexp:= regexp.MustCompile("[1-9]")
flag := Myregexp.Match([]byte("didi"))

6)判断Regexp正则对象是否与给定的字符串匹配。

func (re *Request) MatchString(s string) bool
Myregexp:= regexp.Compile("[1-9]")
flag := Myregexp.MatchString("didi"))

7)ReplaceAll()将src中符合正则表达式的部分全部替换成指定内容。

func (re *regexp) ReplaceAll(src,repl []byte) []byte
Myregexp:= regexp.MustCompile("[1-9]")
result := string(Myregexp.ReplaceAll([]byte("dddd"),[]byte("12"))))

8)将字符串按照正则表达式分割成子字符串组成的切片。

func (re *regexp) Split(s string,n int) []string
Myregexp:= regexp.MustCompile("[1-9]")
result := Myregexp.Split("dddd",5)

2 指针

2.1 声明指针

指针变量的类型为 *T,该指针指向一个 T 类型的变量。指针的零值是 nil。

指针的解引用可以获取指针所指向的变量的值,解引用的语法是 *a。

func main() {
    b := 255
    var a *int = &b        //& 操作符用于获取变量的地址。
    fmt.Printf("Type of a is %T\n", a)
    fmt.Println("address of b is", a)
    fmt.Println("value of b is", *a)
}

 2.2 函数传递指针

func change(val *int) {  
    *val = 55
}
func main() {  
    a := 58
    fmt.Println("value of a before function call is",a)
    b := &a
    change(b)
    fmt.Println("value of a after function call is", a)
}

不要向函数传递数组的指针,而应该使用切片

func modify(arr *[3]int) {  
    (*arr)[0] = 90    //a[x] 是 (*a)[x] 的简写形式,(*arr)[0] 可以替换为 arr[0]。
}

func main() {  
    a := [3]int{89, 90, 91}
    modify(&a)
    fmt.Println(a)
}

3 结构体

3.1 结构体声明

1)创建名的结构体(Named Structure)。创建了名为 Employee 的新类型,而它可以用于创建 Employee 类型的结构体变量。

type Employee struct {
    firstName string
    lastName  string
    age,salary       int
}
func main() {

    //creating structure using field names
    emp1 := Employee{
        firstName: "Sam",
        age:       25,
        salary:    500,
        lastName:  "Anderson",
    }

    //creating structure without using field names
    emp2 := Employee{"Thomas", "Paul", 29, 800}

    fmt.Println("Employee 1", emp1)
    fmt.Println("Employee 2", emp2)
}

 2)声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体(Anonymous Structure)。

var employee struct {
    firstName, lastName string
    age,salary int
}
func main() {
    emp3 := struct {
        firstName, lastName string
        age, salary         int
    }{
        firstName: "Andreah",
        lastName:  "Nikola",
        age:       31,
        salary:    5000,
    }

    fmt.Println("Employee 3", emp3)
}

3)访问字段

fmt.Println("First Name:", emp3.firstName)
fmt.Println("Last Name:", emp3.lastName)
fmt.Println("Age:", emp3.age)
fmt.Printf("Salary: $%d", emp3.salary)

3.2 结构体指针

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp8 := &Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", (*emp8).firstName)
    fmt.Println("Age:", (*emp8).age)
}

3.3 匿名字段

当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段(Anonymous Field)。

type Person struct {  
    string
    int
}

func main() {  
    p := Person{"Naveen", 50}
    fmt.Println(p)
    p.string = "King"
    p.int = 100
    fmt.Println(p)
}

3.4 结构体替代类

Go 不支持类,而是提供了结构体。结构体中可以添加方法。这样可以将数据和操作数据的方法绑定在一起,实现与类相似的效果。(方法将在第4节介绍)

1)在你的 Go 工作区创建一个名为 oop 的文件夹。在 opp 中再创建子文件夹 employee。在 employee 内,创建一个名为 employee.go 的文件。

文件夹结构会是这样:

workspacepath -> oop -> employee -> employee.go

package employee

type Employee struct {  
    FirstName   string
    LastName    string
    TotalLeaves int
    LeavesTaken int
}

func (e Employee) LeavesRemaining() {  
    fmt.Printf("%s %s has %d leaves remaining", e.FirstName, e.LastName, (e.TotalLeaves - e.LeavesTaken))
}

在上述程序里,首先指定了该文件属于 employee 包。然后声明了一个 Employee 结构体。其次,结构体 Employee 添加了一个名为 LeavesRemaining 的方法。

2)接着在 oop 文件夹里创建一个文件,命名为 main.go。

现在目录结构如下所示:

workspacepath -> oop -> employee -> employee.go  
workspacepath -> oop -> main.go

package main

import "oop/employee"

func main() {  
    e := employee.Employee {
        FirstName: "Sam",
        LastName: "Adolf",
        TotalLeaves: 30,
        LeavesTaken: 20,
    }
    e.LeavesRemaining()
}

3)使用New函数

package employee

import (  
    "fmt"
)

type employee struct {  
    firstName   string
    lastName    string
    totalLeaves int
    leavesTaken int
}

func New(firstName string, lastName string, totalLeave int, leavesTaken int) employee {  
    e := employee {firstName, lastName, totalLeave, leavesTaken}
    return e
}

func (e employee) LeavesRemaining() {  
    fmt.Printf("%s %s has %d leaves remaining", e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken))
}

我们把 Employee 结构体的首字母改为小写 e,也就是将 type Employee struct 改为了 type employee struct。通过这种方法,我们把 employee 结构体变为了不可引用的,防止其他包对它的访问。

package main  

import "oop/employee"

func main() {  
    e := employee.New("Sam", "Adolf", 30, 20)
    e.LeavesRemaining()
}

3.5 组合取代继承

在 Go 中,通过在结构体内嵌套结构体,可以实现组合。

type author struct {  
    firstName string
    lastName  string
    bio       string
}

func (a author) fullName() string {  
    return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

type post struct {  
    title   string
    content string
    author    //嵌套author结构体
}

func (p post) details() {  
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.fullName())
    fmt.Println("Bio: ", p.bio)
}

type website struct {  
 posts []post    //嵌套post结构体的切片
}

func (w website) contents() {  
    fmt.Println("Contents of Website\n")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}

4 方法

方法其实就是一个函数,在 func 这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的。

func (t Type) methodName(parameter list) {
}
type Employee struct {
    name     string
    salary   int
    currency string
}

/*
  displaySalary() 方法将 Employee 做为接收器类型
*/
func (e Employee) displaySalary() {
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}

/*
displaySalary2()方法被转化为一个函数,把 Employee 当做参数传入。
*/
func displaySalary2(e Employee) {
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}

func main() {
    emp1 := Employee {
        name:     "Sam Adolf",
        salary:   5000,
        currency: "$",
    }
    emp1.displaySalary() // 调用 Employee 类型的 displaySalary() 方法
    displaySalary2(emp1)
}

5 接口

5.1 声明接口

在 Go 语言中,接口就是方法签名(Method Signature)的集合。当一个类型定义了接口中的所有方法,我们称它实现了该接口。

//interface definition
type VowelsFinder interface {  
    FindVowels() []rune
}

type MyString string

//MyString implements VowelsFinder
func (ms MyString) FindVowels() []rune {  
    。。。
    return vowels
}

func main() {  
    name := MyString("Sam Anderson")
    var v VowelsFinder
    v = name // possible since MyString implements VowelsFinder
    fmt.Printf("Vowels are %c", v.FindVowels())

}

5.2 空接口

没有包含方法的接口称为空接口。空接口表示为 interface{}。由于空接口没有方法,因此所有类型都实现了空接口。

func describe(i interface{}) {  
    fmt.Printf("Type = %T, value = %v\n", i, i)
}

func main() {  
    s := "Hello World"
    describe(s)
    i := 55
    describe(i)
}

5.3 类型断言与类型选择

类型断言用于提取接口的底层值(Underlying Value)。

在语法 i.(T) 中,接口 i 的具体类型是 T,该语法用于获得接口的底层值。

func assert(i interface{}) {  
    s := i.(int) //get the underlying int value from i
    fmt.Println(s)
}
func main() {  
    var s interface{} = 56
    assert(s)

类型选择的语法类似于类型断言。类型断言的语法是 i.(T),而对于类型选择,类型 T 由关键字 type 代替。

func findType(i interface{}) {  
    switch i.(type) {
    case string:
        fmt.Printf("I am a string and my value is %s\n", i.(string))
    case int:
        fmt.Printf("I am an int and my value is %d\n", i.(int))
    default:
        fmt.Printf("Unknown type\n")
    }
}

5.4 指针接收实现接口

type Describer interface {  
    Describe()
}
type Person struct {  
    name string
    age  int
}

func (p Person) Describe() { // 使用值接收者实现  
    fmt.Printf("%s is %d years old\n", p.name, p.age)
}

type Address struct {
    state   string
    country string
}

func (a *Address) Describe() { // 使用指针接收者实现
    fmt.Printf("State %s Country %s", a.state, a.country)
}

func main() {  
    var d1 Describer
    p1 := Person{"Sam", 25}
    d1 = p1
    d1.Describe()
    //指针方式
    p2 := Person{"James", 32}
    d1 = &p2
    d1.Describe()
}

5.5 接口嵌套

尽管 Go 语言没有提供继承机制,但可以通过嵌套其他的接口,创建一个新接口。

type SalaryCalculator interface {  
    DisplaySalary()
}

type LeaveCalculator interface {  
    CalculateLeavesLeft() int
}

type EmployeeOperations interface {  
    SalaryCalculator
    LeaveCalculator
}

type Employee struct {  
    firstName string
    lastName string
    basicPay int
    pf int
    totalLeaves int
    leavesTaken int
}

func (e Employee) DisplaySalary() {  
    fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf))
}

func (e Employee) CalculateLeavesLeft() int {  
    return e.totalLeaves - e.leavesTaken
}

func main() {  
    e := Employee {
        firstName: "Naveen",
        lastName: "Ramanathan",
        basicPay: 5000,
        pf: 200,
        totalLeaves: 30,
        leavesTaken: 5,
    }
    var empOp EmployeeOperations = e   //使用嵌套接口
    empOp.DisplaySalary()
    fmt.Println("\nLeaves left =", empOp.CalculateLeavesLeft())
}

5.6 多态

 所有实现了接口的类型,都可以把它的值保存在一个接口类型的变量中。在 Go 中,我们使用接口的这种特性来实现多态。

type Income interface {  
    calculate() int
    source() string
}

type FixedBilling struct {  
    projectName string
    biddedAmount int
}

type TimeAndMaterial struct {  
    projectName string
    noOfHours  int
    hourlyRate int
}

func (fb FixedBilling) calculate() int {  
    return fb.biddedAmount
}

func (fb FixedBilling) source() string {  
    return fb.projectName
}

func (tm TimeAndMaterial) calculate() int {  
    return tm.noOfHours * tm.hourlyRate
}

func (tm TimeAndMaterial) source() string {  
    return tm.projectName
}

func calculateNetIncome(ic []Income) {  
    var netincome int = 0
    for _, income := range ic {
        fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())
        netincome += income.calculate()
    }
    fmt.Printf("Net income of organisation = $%d", netincome)
}

func main() {  
    project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
    project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
    project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
    incomeStreams := []Income{project1, project2, project3}
    calculateNetIncome(incomeStreams)
}

calculateNetIncome函数接收一个 Income 接口类型的切片作为参数。该函数会遍历这个接口切片,并依个调用 calculate() 方法,计算出总收入。该函数同样也会通过调用 source() 显示收入来源。根据 Income 接口的具体类型,程序会调用不同的 calculate() 和 source() 方法。于是,我们在 calculateNetIncome 函数中就实现了多态。 

6 并发

并发是指立即处理多个任务的能力。并行是指同时处理多个任务。

》》》假如在他晨跑时,鞋带突然松了。于是他停下来,系一下鞋带,接下来继续跑。这个例子就是典型的并发。这个人能够一下搞定跑步和系鞋带两件事,即立即处理多个任务。

》》》假如这个人在慢跑时,还在用他的 iPod 听着音乐。在这里,他是在跑步的同时听音乐,也就是同时处理多个任务。这称之为并行。

Go 编程语言原生支持并发。Go 使用 Go 协程(Goroutine) 和信道(Channel)来处理并发。

6.1 协程

Go 协程是与其他函数或方法一起并发运行的函数或方法。Go 协程可以看作是轻量级线程。与线程相比,创建一个 Go 协程的成本很小。因此在 Go 应用中,常常会看到有数以千计的 Go 协程并发地运行。

如何创建协程 :

调用函数或者方法时,在前面加上关键字 go,可以让一个新的 Go 协程并发地运行。

func hello() {
    fmt.Println("Hello world goroutine")
}
func main() {
    go hello()
    fmt.Println("main function")
}

 会发现主函数并不会等待go协程, 因为hello() 函数与 main() 函数会并发地执行。主函数会运行在一个特有的 Go 协程上,它称为 Go 主协程(Main Goroutine)。

 可以加上时间限制,让主协程等待一下

func main() {  
    go hello()
    time.Sleep(1 * time.Second)
    fmt.Println("main function")
}

6.2 信道

信道可以想像成 Go 协程之间通信的管道。如同管道中的水会从一端流到另一端,通过使用信道,数据也可以从一端发送,在另一端接收。

1)信道的声明

所有信道都关联了一个类型。信道只能运输这种类型的数据,而运输其他类型的数据都是非法的。

chan T 表示 T 类型的信道。应用 make 来定义信道,信道的零值为 nil。

func main() {  
    var a chan int
    if a == nil {
        fmt.Println("channel a is nil, going to define it")
        a = make(chan int)
        fmt.Printf("Type of a is %T", a)
    }
}

2)数据传送

data := <- a // 读取信道 a  
a <- data // 写入信道 a

发送与接收默认是阻塞的。当把数据发送到信道时,程序控制 会在发送数据的语句处 发生阻塞,直到有其它 Go 协程从信道读取到数据,才会解除阻塞。 

信道的这种特性能够帮助 Go 协程之间进行高效的通信,不需要用到其他编程语言常见的显式锁或条件变量。

func hello(done chan bool) {
	fmt.Println("Start write data")
	done <- true
}
func main() {
	done := make(chan bool)
	go hello(done)
	<-done
	fmt.Println("read data ")
}

 3)死锁

使用信道需要考虑的一个重点是死锁。当 Go 协程给一个信道发送数据时,照理说会有其他 Go 协程来接收数据。如果没有的话,程序就会在运行时触发 panic,形成死锁。

同理,当有 Go 协程等着从一个信道接收数据时,我们期望其他的 Go 协程会向该信道写入数据,要不然程序就会触发 panic。

4)单向通信

chan<- T 以创建单向信道,这种信道只能接收数据。也可以创建只发送数据的单向信道。

func sendData(sendch chan<- int) {  
    sendch <- 10
}

func main() {  
    sendch := make(chan<- int)
    go sendData(sendch)
    fmt.Println(<-sendch)
}

5)关闭信道

数据发送方可以关闭信道,通知接收方这个信道不再有数据发送过来。

当从信道接收数据时,接收方可以多用一个变量来检查信道是否已经关闭。

v, ok := <- ch
func producer(chnl chan int) {  
    for i := 0; i < 10; i++ {
        chnl <- i
    }
    close(chnl)
}
func main() {  
    ch := make(chan int)
    go producer(ch)
    for {
        v, ok := <-ch
        if ok == false {
            break
        }
        fmt.Println("Received ", v, ok)
    }
}

6.3 缓冲信道

1)创建缓冲信道

ch := make(chan type, capacity)   

 capacity 应该大于 0。无缓冲信道的容量默认为 0。

func main() {  
    ch := make(chan string, 2)
    ch <- "naveen"
    ch <- "paul"
    fmt.Println(<- ch)
    fmt.Println(<- ch)
}

我们创建了一个缓冲信道,其容量为 2。由于该信道的容量为 2,因此可向它写入两个字符串,而且不会发生阻塞。

 2)容量与长度

缓冲信道的容量是指信道可以存储的值的数量。我们在使用 make 函数创建缓冲信道的时候会指定容量大小。

缓冲信道的长度是指信道中当前排队的元素个数。

func main() {  
    ch := make(chan string, 3)
    ch <- "naveen"
    ch <- "paul"
    fmt.Println("capacity is", cap(ch))
    fmt.Println("length is", len(ch))
    fmt.Println("read value", <-ch)
    fmt.Println("new length is", len(ch))
}

 6.4 WaitGroup

1)WaitGroup

WaitGroup 用于等待一批 Go 协程执行结束。程序控制会一直阻塞,直到这些协程全部执行完毕。

func process(i int, wg *sync.WaitGroup) {  
    fmt.Println("started Goroutine ", i)
    time.Sleep(2 * time.Second)
    fmt.Printf("Goroutine %d ended\n", i)
    wg.Done()
}

func main() {  
    no := 3
    var wg sync.WaitGroup
    for i := 0; i < no; i++ {
        wg.Add(1)
        go process(i, &wg)
    }
    wg.Wait()
    fmt.Println("All go routines finished executing")
}

WaitGroup 是一个结构体类型,我们创建了 WaitGroup 类型的变量,其初始值为零值。WaitGroup 使用计数器来工作。当我们调用 WaitGroup 的 Add 并传递一个 int 时,WaitGroup 的计数器会加上 Add 的传参。要减少计数器,可以调用 WaitGroup 的 Done() 方法。Wait() 方法会阻塞调用它的 Go 协程,直到计数器变为 0 后才会停止阻塞。

6.5  select

select 语句用于在多个发送/接收信道操作中进行选择。select 语句会一直阻塞,直到发送/接收操作准备就绪。如果有多个信道操作准备完毕,select 会随机地选取其中之一执行。该语法与 switch 类似,所不同的是,这里的每个 case 语句都是信道操作。

func server1(ch chan string) {  
    time.Sleep(6 * time.Second)
    ch <- "from server1"
}
func server2(ch chan string) {  
    time.Sleep(3 * time.Second)
    ch <- "from server2"

}
func main() {  
    output1 := make(chan string)
    output2 := make(chan string)
    go server1(output1)
    go server2(output2)
    select {
    case s1 := <-output1:
        fmt.Println(s1)
    case s2 := <-output2:
        fmt.Println(s2)
    }
}

6.6 Mutex 

1)临界区

当程序并发地运行时,多个 Go 协程不应该同时访问那些修改共享资源的代码。这些修改共享资源的代码称为临界区。

2)Mutex

Mutex 用于提供一种加锁机制(Locking Mechanism),可确保在某时刻只有一个协程在临界区运行,以防止出现竞态条件。

Mutex 可以在 sync 包内找到。Mutex 定义了两个方法:Lock 和 Unlock。所有在 Lock 和 Unlock 之间的代码,都只能由一个 Go 协程执行,于是就可以避免竞态条件。

import (  
    "fmt"
    "sync"
    )
var x  = 0  
func increment(wg *sync.WaitGroup, m *sync.Mutex) {  
    m.Lock()
    x = x + 1
    m.Unlock()
    wg.Done()   
}
func main() {  
    var w sync.WaitGroup
    var m sync.Mutex
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go increment(&w, &m)
    }
    w.Wait()
    fmt.Println("final value of x", x)
}

7 异常处理

7.1 error接口

error是一个接口类型,包含一个Error()方法。

type error interface
{
    Error() string
}

在Go语言中处理错误的方式通常是将返回的错误与nil进行比较。nil值表示没有发生错误,而非nil值表示出现错误。

import (
    "errors"
    "fmt"
)
func main(){
res , err := Sqrt(-100)
if err != nil {
    fmt.Println(err)
    //fmt.Println(err.Error())
} else {
        fmt.Println(res)
    }
}

errors包下的New()函数返回error对象,errors.New()函数创建新的错误。

//1、创建error对象的方式1
    err1 := errors.New("自己创建的错误!")
//2、创建error对象的方式2
    err2 := fmt.Errorf("错误的类型%d", 10)

7.2 panic和recover

1)panic

panic()是一个内建函数,可以中断原有的控制流程。

func panic(interface{})
func fullName(firstName *string, lastName *string) {  
    if firstName == nil {
        panic("runtime error: first name cannot be nil")
    }
    if lastName == nil {
        panic("runtime error: last name cannot be nil")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}

func main() {  
    firstName := "Elon"
    fullName(&firstName, nil)
    fmt.Println("returned normally from main")
}

当函数发生 panic 时,它会终止运行,在执行完所有的延迟函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪,最后程序终止。

2)recover

recover 是一个内建函数,用于重新获得 panic 协程的控制。

func recover() interface{}
func recoverName() {  
    if r := recover(); r!= nil {
        fmt.Println("recovered from ", r)
    }
}

func fullName(firstName *string, lastName *string) {  
    defer recoverName()
    if firstName == nil {
        panic("runtime error: first name cannot be nil")
    }
    if lastName == nil {
        panic("runtime error: last name cannot be nil")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}

func main() {  
    defer fmt.Println("deferred call in main")
    firstName := "Elon"
    fullName(&firstName, nil)
    fmt.Println("returned normally from main")
}

8 其他

8.1 反射

反射就是程序能够在运行时检查变量和值,求出它们的类型。

在 Go 语言中,reflect 实现了运行时反射。reflect 包会帮助识别 interface{} 变量的底层具体类型和具体值。

import (
    "fmt"
    "reflect"
)

type order struct {
    ordId      int
    customerId int
}

func createQuery(q interface{}) {
    t := reflect.TypeOf(q)    
    v := reflect.ValueOf(q)
    fmt.Println("Type ", t)
    fmt.Println("Value ", v)


}
func main() {
    o := order{
        ordId:      456,
        customerId: 56,
    }
    createQuery(o)

}

8.2 文件操作

1)fileinfo

//绝对路径
    fileInfo , err := os.Stat("/Users/xxx/Documents/1.png")
//相对路径
    fileInfo , err = os.Stat("./files/1.docx")
if err !=nil {
        fmt.Println("err:" , err.Error())
    } else {
        //文件名
        fmt.Println(fileInfo.Name())
        //是否是目录
        fmt.Println(fileInfo.IsDir())
        //文件尺寸大小
        fmt.Println(fileInfo.Size())
        //mode 权限
        fmt.Println(fileInfo.Mode())
        //文件最后修改时间
        fmt.Println(fileInfo.ModTime())
    }

 2)filepath

3)创建

os.MKdir()仅创建一层目录。

os.MKdirAll()创建多层目录。

os.Create(name string) (file *File, err Error根据提供的文件名创建新的文件,返回一个文件对象,如果文件存在,会将其覆盖。

os.NewFile(fd uintptr, name string) *File  根据文件描述符创建相应的文件,返回一个文件对象

os.Open(name string) (file *File, err Error)只读方式打开一个名称为name的文件,函数本质上是在调用os.OpenFile()函数。

os.OpenFile(name string, flag int, perm uint32) (file *File, err Error)
        第一个参数:filename,文件名称。

        第二个参数:mode,文件的打开方式。可同时使用多个方式,用“|”分开。

        

        第三个参数:perm,文件的权限。文件不存在时创建文件,需要指定权限。

 os.Close()关闭文件

os.Remove(name string) Error 删除文件名为name的文件

4)文件读写

file.Read(b []byte) (n int, err Error)从文件中开始读取数据,返回值n是实际读取的字节数。如果读取到文件末尾,n为0或err为io.EOF。

file.Write(b []byte) (n int, err Error)写入byte类型的信息到文件

file.WriteAt(b []byte, off int64) (n int, err Error)在指定位置开始写入byte类型的信息

file.WriteString(s string) (ret int, err Error)写入string信息到文件
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值