2019年12月16日16:57:04

5.接口

2019年11月01日15:56:09

5.1 duck typing

1.

2.

接口

3.介绍

Go 语言的接口设计是非侵入式的,接口编写者无须知道接口被哪些类型实现。

而接口实现者只需知道实现的是什么样子的接口,但无须指明实现哪一个接口。

编译器知道最终编译时使用哪个类型实现哪个接口,或者接口应该由谁来实现。

每个接口类型由数个方法组成。接口的形式代码如下:

type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2

}

对各个部分的说明:

  • 接口类型名:使用 type 将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加 er,如有写操作的接口叫 Writer,有字符串功能的接口叫 Stringer,有关闭功能的接口叫 Closer 等。
  • 方法名:当方法名首字母是大写时,且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。
  • 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以被忽略,例如:
type writer interface{
Write([]byte) error
}

3.接口由使用者定义

4.

接口的值类型

5.type assertion 类型断言

判断r的真实类型,是不是mock.Retriever类型实现的。

r.(*mock.Retriever)

r.(type)

// Type assertion
if mockRetriever, ok := r.(*mock.Retriever); ok {
fmt.Println(mockRetriever.Contents)
} else {
fmt.Println("r is not a mock retriever")
} fmt.Println(
"Try a session with mockRetriever")
fmt.Println(session(&mockRetriever))
}

6.interface里一般有类型和值

fmt.println("%T %v ",r,r)

func inspect(r Retriever) {

	fmt.Println("Inspecting", r)
fmt.Printf(" > Type:%T Value:%v\n", r, r)
fmt.Print(" > Type switch: ") switch v := r.(type) {
case *mock.Retriever:
fmt.Println("Contents:", v.Contents)
case *real.Retriever:
fmt.Println("UserAgent:", v.UserAgent)
}
fmt.Println()
}

7.接口变量里有什么

8.接口变量自带指针

9.接口变量同样采用值传递,几乎不需要使用接口的指针

10.指针接受者实现只能以指针方式使用;值接受者都可以

var r Retriever

	mockRetriever := mock.Retriever{
Contents: "this is a fake imooc.com"}
r = &mockRetriever
inspect(r) r = &real.Retriever{
UserAgent: "Mozilla/5.0",
TimeOut: time.Minute,
}

11.查看接口类型

interface{}支持任何类型

type Queue []interface{}

func (q *Queue) Push(v interface{}) {
*q=append(*q,v) }

Type Assertion

Type Switch

2019年11月03日

5.2 接口的组合

2019年11月03日13:33:08

1.新定义一个接口——为了组合

type Poster interface {
Post(url string,
form map[string]string) string
} func post(poster Poster) {
poster.Post(url,
map[string]string{
"name": "ccmouse",
"course": "golang",
})
}

2.定义一个组合接口

type RetrieverPoster interface {
Retriever
Poster
}

3.mockRetriever接口实现了Post方法

//mockretriever.go
func (r *Retriever) Post(url string,
form map[string]string) string {
r.Contents = form["contents"]
return "ok"
} //main.go
func session(s RetrieverPoster) string {
s.Post(url, map[string]string{
"contents": "another faked imooc.com",
})
return s.Get(url)
} func main() {
var r Retriever mockRetriever := mock.Retriever{
Contents: "this is a fake imooc.com"}
r = &mockRetriever
inspect(r) r = &real.Retriever{
UserAgent: "Mozilla/5.0",
TimeOut: time.Minute,
}
inspect(r) fmt.Println(
"Try a session with mockRetriever")
fmt.Println(session(&mockRetriever))
}

6.函数式编程

2019年11月03日14:53:11

1.


#### 2.闭包 <img src="https://tva1.sinaimg.cn/large/006y8mN6ly1g8kwses02tj313u0u0h1k.jpg" alt="image-20191103150946598" style="zoom:25%;" /> #### 3.匿名函数 Go语言支持匿名函数,即在需要使用函数时再定义函数,匿名函数没有函数名只有函数体,函数可以作为一种类型被赋值给函数类型的变量,匿名函数也往往以变量方式传递,这与C语言的回调函数比较类似,不同的是,Go语言支持随时在代码里定义匿名函数。 **定义一个匿名函数** 匿名函数的定义格式如下:

func(参数列表)(返回参数列表){

函数体

}


匿名函数的定义就是没有名字的普通函数定义。 **在定义时调用匿名函数** 匿名函数可以在声明后调用,例如: ```go
func(data int) {
fmt.Println(
"hello", data)
}(100)

注意第3行} (100)

将匿名函数赋值给变量

匿名函数可以被赋值,例如:

// 将匿名函数体保存到f()中
f := func(data int) {
fmt.Println("hello", data)
} // 使用f()调用
f(100)

匿名函数的用途非常广泛,它本身就是一种值,可以方便地保存在各种容器中实现回调函数和操作封装。

4.闭包的记忆效应

被捕获到闭包中的变量让闭包本身拥有了记忆效应,闭包中的逻辑可以修改闭包捕获的变量,变量会跟随闭包生命期一直存在,闭包本身就如同变量一样拥有了记忆效应。

累加器的实现:

package main
import (
"fmt"
)
// 提供一个值, 每次调用函数会指定对值进行累加
func Accumulate(value int) func() int {
// 返回一个闭包
return func() int {
// 累加
value++
// 返回一个累加值
return value
}
}
func main() {
// 创建一个累加器, 初始值为1
accumulator := Accumulate(1)
// 累加1并打印
fmt.Println(accumulator())
fmt.Println(accumulator())
// 打印累加器的函数地址
fmt.Printf("%p\n", accumulator)
// 创建一个累加器, 初始值为1
accumulator2 := Accumulate(10)
// 累加1并打印
fmt.Println(accumulator2())
// 打印累加器的函数地址
fmt.Printf("%p\n", accumulator2)
}

代码说明如下:

  • 第 8 行,累加器生成函数,这个函数输出一个初始值,调用时返回一个为初始值创建的闭包函数。
  • 第 11 行,返回一个闭包函数,每次返回会创建一个新的函数实例。
  • 第 14 行,对引用的 Accumulate 参数变量进行累加,注意 value 不是第 11 行匿名函数定义的,但是被这个匿名函数引用,所以形成闭包。
  • 第 17 行,将修改后的值通过闭包的返回值返回。
  • 第 24 行,创建一个累加器,初始值为 1,返回的 accumulator 是类型为 func()int 的函数变量。
  • 第 27 行,调用 accumulator() 时,代码从 11 行开始执行匿名函数逻辑,直到第 17 行返回。
  • 第 32 行,打印累加器的函数地址。

对比输出的日志发现 accumulator 与 accumulator2 输出的函数地址不同,因此它们是两个不同的闭包实例。

7.错误处理和资源管理

7.1 defer调用

2019年11月03日16:00:50

1.defer调用来实现资源管理

2.确保调用在函数结束时发生

3.参数在defer语句时计算

4.defer列表为后进先出

5.何时使用defer调用

Open/Close

Lock/unlock

PrintHeader/PrintFooter

6.源码

package main

import (
"fmt"
"os"
"u2pppw/src/functional/fib" "bufio" ) func tryDefer() {
for i := 0; i < 100; i++ {
defer fmt.Println(i)
if i == 30 {
// Uncomment panic to see
// how it works with defer
// panic("printed too many")
}
}
} func writeFile(filename string) {
file, err := os.OpenFile(filename,
os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666) if err != nil {
if pathError, ok := err.(*os.PathError); !ok {
panic(err)
} else {
fmt.Printf("%s, %s, %s\n",
pathError.Op,
pathError.Path,
pathError.Err)
}
return
}
defer file.Close() writer := bufio.NewWriter(file)
defer writer.Flush() f := fib.Fibonacci()
for i := 0; i < 20; i++ {
fmt.Fprintln(writer, f())
}
} func main() {
tryDefer()
writeFile("fib.txt")
}

7.2 错误处理概念

2019年11月03日16:57:12

1.为了防止程序挂掉——错误处理

	if err != nil {
if pathError, ok := err.(*os.PathError); !ok {
panic(err)
} else {
fmt.Printf("%s, %s, %s\n",
pathError.Op,
pathError.Path,
pathError.Err)
}
return
}

服务器统一出错处理

1.如何实现统一的错误处理逻辑

2.起一个服务端读取内容

读取方法

const prefix = "/list/"

func HandleFileList(writer http.ResponseWriter,
request *http.Request) error {
fmt.Println()
if strings.Index(
request.URL.Path, prefix) != 0 {
return userError(
fmt.Sprintf("path %s must start "+
"with %s",
request.URL.Path, prefix))
}
path := request.URL.Path[len(prefix):]
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close() all, err := ioutil.ReadAll(file)
if err != nil {
return err
} writer.Write(all)
return nil
}

处理错误的包装方法——使用函数式编程

type appHandler func(writer http.ResponseWriter,
request *http.Request) error func errWrapper(
handler appHandler) func(
http.ResponseWriter, *http.Request) {
return func(writer http.ResponseWriter,
request *http.Request) {
// panic
defer func() {
if r := recover(); r != nil {
log.Printf("Panic: %v", r)
http.Error(writer,
http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
}
}() err := handler(writer, request) if err != nil {
log.Printf("Error occurred "+
"handling request: %s",
err.Error()) // user error
if userErr, ok := err.(userError); ok {
http.Error(writer,
userErr.Message(),
http.StatusBadRequest)
return
} // system error
code := http.StatusOK
switch {
case os.IsNotExist(err):
code = http.StatusNotFound
case os.IsPermission(err):
code = http.StatusForbidden
default:
code = http.StatusInternalServerError
}
http.Error(writer,
http.StatusText(code), code)
}
}
}

main方法

func main() {
http.HandleFunc("/",
errWrapper(filelisting.HandleFileList)) err := http.ListenAndServe(":8888", nil)
if err != nil {
panic(err)
}
}

3.源码

main.go

package main

import (
"log"
"net/http"
_ "net/http/pprof"
"os"
"u2pppw/src/errhandling/filelistingserver/filelisting"
) type appHandler func(writer http.ResponseWriter,
request *http.Request) error func errWrapper(
handler appHandler) func(
http.ResponseWriter, *http.Request) {
return func(writer http.ResponseWriter,
request *http.Request) {
// panic
defer func() {
if r := recover(); r != nil {
log.Printf("Panic: %v", r)
http.Error(writer,
http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
}
}() err := handler(writer, request) if err != nil {
log.Printf("Error occurred "+
"handling request: %s",
err.Error()) // user error
if userErr, ok := err.(userError); ok {
http.Error(writer,
userErr.Message(),
http.StatusBadRequest)
return
} // system error
code := http.StatusOK
switch {
case os.IsNotExist(err):
code = http.StatusNotFound
case os.IsPermission(err):
code = http.StatusForbidden
default:
code = http.StatusInternalServerError
}
http.Error(writer,
http.StatusText(code), code)
}
}
} type userError interface {
error
Message() string
} func main() {
http.HandleFunc("/",
errWrapper(filelisting.HandleFileList)) err := http.ListenAndServe(":8888", nil)
if err != nil {
panic(err)
}
}

handle.go

package filelisting

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
) const prefix = "/list/" type userError string func (e userError) Error() string {
return e.Message()
} func (e userError) Message() string {
return string(e)
} func HandleFileList(writer http.ResponseWriter,
request *http.Request) error {
fmt.Println()
if strings.Index(
request.URL.Path, prefix) != 0 {
return userError(
fmt.Sprintf("path %s must start "+
"with %s",
request.URL.Path, prefix))
}
path := request.URL.Path[len(prefix):]
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close() all, err := ioutil.ReadAll(file)
if err != nil {
return err
} writer.Write(all)
return nil
}

7.3panic和recover

2019年11月04日14:00:22

1. panic

1.停止当前函数执行

2.一直向上返回,执行每一层的defer

3.如果没有遇见recover,程序退出

2. recover

1.仅在defer调用中使用

defer func() {
err:=recover()
}()

2.获取panic的值

如果无法处理,就可以重新panic

package main

import (
"fmt"
) func tryRecover() {
defer func() {
r := recover()
if r == nil {
fmt.Println("Nothing to recover. " +
"Please try uncomment errors " +
"below.")
return
}
if err, ok := r.(error); ok {
fmt.Println("Error occurred:", err)
} else {
panic(fmt.Sprintf(
"I don't know what to do: %v", r))
}
}() // Uncomment each block to see different panic
// scenarios.
// Normal error
//panic(errors.New("this is an error")) // Division by zero
//b := 0
//a := 5 / b
//fmt.Println(a) // Causes re-panic
panic(123)
} func main() {
tryRecover()
}

8.goroutine

2019年11月04日14:49:18

1.并发编程

package main

import (
"fmt"
"time"
) func main() {
for i := 0; i < 1000; i++ {
go func(i int) {
for {
fmt.Printf("Hello from "+
"goroutine %d\n", i)
}
}(i)
}
time.Sleep(time.Minute)
}

2.协程 Coroutine

轻量级线程

非抢占式多任务处理,由协程主动交出控制权

多个协程可能在一个或多个线程上运行

func main() {

	var a [10]int
for i:=0;i<10;i++{
go func(i int){
for{
//fmt.Println("hello %d\n",i)
a[i]++
runtime.Gosched()
}
}(i)
} time.Sleep(time.Millisecond)
fmt.Println(a) }

3.任何函数只需加上go就能送给调度器运行

4.不需要在定义时区分时都是异步函数

5.调度器在合适的点进行切换

6.使用-race来检测数据访问冲突

7.goroutine可能的切换点

I/O,select

channel

等待锁

函数调用

runtime,Gosched()

9.channel

2019年11月04日15:30:28

1.介绍

Go语言中的通道(channel)是一种特殊的类型。在任何时候,同时只能有一个 goroutine 访问通道进行发送和获取数据。goroutine 间通过通道就可以通信。

通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。

2.声明通道类型

通道本身需要一个类型进行修饰,就像切片类型需要标识元素类型。通道的元素类型就是在其内部传输的数据类型,声明如下:

var 通道变量 chan 通道类型
  • 通道类型:通道内的数据类型。
  • 通道变量:保存通道的变量。

chan 类型的空值是 nil,声明后需要配合 make 后才能使用。

3.创建通道

通道是引用类型,需要使用 make 进行创建,格式如下:

通道实例 := make(chan 数据类型)
  • 数据类型:通道内传输的元素类型。
  • 通道实例:通过make创建的通道句柄。

请看下面的例子:

ch1 := make(chan int)                 // 创建一个整型类型的通道
ch2 := make(chan interface{}) // 创建一个空接口类型的通道, 可以存放任意格式
type Equip struct{ /* 一些字段 */ }
ch2 := make(chan *Equip) // 创建Equip指针类型的通道, 可以存放*Equip

4.发送数据

// 创建一个空接口通道
ch := make(chan interface{})
// 将0放入通道中
ch <- 0
// 将hello字符串放入通道中
ch <- "hello"

10.beego介绍及搭建

2019年12月06日13:28:50

1.介绍

  • Beego是一个能够快速开发Go应用程序的HTTP框架, 它可以用来迅速的开发API, 网络APP(网站)和后端服务
  • Beego是一个MVC的框架

beego有八个模块,分别是

  1. cache
  2. config:
  3. context:
  4. httplibs: curl函数
  5. logs:
  6. orm
  7. session
  8. toolbox

2.优势

beego是一个类似tornado的Go应用框架,采用了RESTFul的方式来实现应用框架,是一个超轻量级的框架,主要有如下的特点:

  • 支持MVC的方式,用户只需要关注逻辑,实现对应method的方法即可
  • 支持websocket,通过自定义Handler实现集成sockjs等方式实现
  • 支持自定义路由,支持各种方式的路由,正则、语意均支持,类似sinatra
  • session集成,支持memory、file、redis、mysql等存储
  • 表单处理自动化解析,用户可以很方便的获取数据
  • 日志分级系统,用户可以很方便的调试和应用日志记录
  • 自定义配置文件,支持ini格式的文本配置,可以方便的在系统中调参数
  • 采用了Go内置的模板,集成实现了很多Web开发中常用的函数

3.环境搭建

beego 的安装是典型的 Go 安装包的形式:

go get github.com/astaxie/beego

Go 升级,通过该方式用户可以升级 beego 框架,强烈推荐该方式:

go get -u github.com/astaxie/beego

源码下载升级,用户访问 https://github.com/astaxie/beego ,下载源码,然后覆盖到 $GOPATH/src/github.com/astaxie/beego 目录,然后通过本地执行安装就可以升级了:

go install  github.com/astaxie/beego

bee 工具简介

bee 工具是一个为了协助快速开发 beego 项目而创建的项目,通过 bee 您可以很容易的进行 beego 项目的创建、热编译、开发、测试、和部署。

bee 工具的安装

您可以通过如下的方式安装 bee 工具:

go get github.com/beego/bee

安装完之后,bee 可执行文件默认存放在 $GOPATH/bin 里面,所以您需要把 $GOPATH/bin 添加到您的环境变量中,才可以进行下一步。

new 命令

new 命令是新建一个 Web 项目,我们在命令行下执行 bee new <项目名> 就可以创建一个新的项目。但是注意该命令必须在 $GOPATH/src 下执行。最后会在 $GOPATH/src 相应目录下生成如下目录结构的项目:

bee new myproject
[INFO] Creating application...
/gopath/src/myproject/
/gopath/src/myproject/conf/
/gopath/src/myproject/controllers/
/gopath/src/myproject/models/
/gopath/src/myproject/static/
/gopath/src/myproject/static/js/
/gopath/src/myproject/static/css/
/gopath/src/myproject/static/img/
/gopath/src/myproject/views/
/gopath/src/myproject/conf/app.conf
/gopath/src/myproject/controllers/default.go
/gopath/src/myproject/views/index.tpl
/gopath/src/myproject/main.go
13-11-25 09:50:39 [SUCC] New application successfully created!
myproject
├── conf
│ └── app.conf
├── controllers
│ └── default.go
├── main.go
├── models
├── routers
│ └── router.go
├── static
│ ├── css
│ ├── img
│ └── js
├── tests
│ └── default_test.go
└── views
└── index.tpl 8 directories, 4 files

api 命令

上面的 new 命令是用来新建 Web 项目,不过很多用户使用 beego 来开发 API 应用。所以这个 api 命令就是用来创建 API 应用的,执行命令之后如下所示:

bee api apiproject
create app folder: /gopath/src/apiproject
create conf: /gopath/src/apiproject/conf
create controllers: /gopath/src/apiproject/controllers
create models: /gopath/src/apiproject/models
create tests: /gopath/src/apiproject/tests
create conf app.conf: /gopath/src/apiproject/conf/app.conf
create controllers default.go: /gopath/src/apiproject/controllers/default.go
create tests default.go: /gopath/src/apiproject/tests/default_test.go
create models object.go: /gopath/src/apiproject/models/object.go
create main.go: /gopath/src/apiproject/main.go

这个项目的目录结构如下:

apiproject
├── conf
│ └── app.conf
├── controllers
│ └── object.go
│ └── user.go
├── docs
│ └── doc.go
├── main.go
├── models
│ └── object.go
│ └── user.go
├── routers
│ └── router.go
└── tests
└── default_test.go

从上面的目录我们可以看到和 Web 项目相比,少了 static 和 views 目录,多了一个 test 模块,用来做单元测试的。

同时,该命令还支持一些自定义参数自动连接数据库创建相关 model 和 controller:

bee api [appname] [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]

如果 conn 参数为空则创建一个示例项目,否则将基于链接信息链接数据库创建项目。

run 命令

我们在开发 Go 项目的时候最大的问题是经常需要自己手动去编译再运行,bee run 命令是监控 beego 的项目,通过 fsnotify监控文件系统。但是注意该命令必须在 $GOPATH/src/appname 下执行。

这样我们在开发过程中就可以实时的看到项目修改之后的效果:

bee run
13-11-25 09:53:04 [INFO] Uses 'myproject' as 'appname'
13-11-25 09:53:04 [INFO] Initializing watcher...
13-11-25 09:53:04 [TRAC] Directory(/gopath/src/myproject/controllers)
13-11-25 09:53:04 [TRAC] Directory(/gopath/src/myproject/models)
13-11-25 09:53:04 [TRAC] Directory(/gopath/src/myproject)
13-11-25 09:53:04 [INFO] Start building...
13-11-25 09:53:16 [SUCC] Build was successful
13-11-25 09:53:16 [INFO] Restarting myproject ...
13-11-25 09:53:16 [INFO] ./myproject is running...

我们打开浏览器就可以看到效果 http://localhost:8080/

19.go语言基础学习(下)——2019年12月16日的更多相关文章

  1. 16.go语言基础学习(上)——2019年12月16日

    2019年12月13日10:35:20 1.介绍 2019年10月31日15:09:03 2.基本语法 2.1 定义变量 2019年10月31日16:12:34 1.函数外必须使用var定义变量 va ...

  2. 20.Nodejs基础知识(上)——2019年12月16日

    2019年12月16日18:58:55 2019年10月04日12:20:59 1. nodejs简介 Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触 ...

  3. 21.Nodejs基础知识(下)——2019年12月16日

    2019年10月04日16:56:23 7. 模块 7.1 暴露一个类,字段 var bar = require("./bar.js"); var msg = "你好&q ...

  4. 36.React基础介绍——2019年12月24日

    2019年12月24日16:47:12 2019年10月25日11:24:29 主要介绍react入门知识. 1.jsx语法介绍 1.1 介绍 jsx语法是一种类似于html标签的语法,它的作用相当于 ...

  5. 日常Git使用——2019年12月11日16:19:03

    1.git介绍 1.1 什么是git? 什么是Git? 比如一个项目,两个人同时参与开发,那么就把这个项目放在一个公共的地方,需要的时候都可以去获取,有什么改动,都可以进行提交. 为了做到这一点,就需 ...

  6. AHKManager.ahk AHK管理器 2019年12月15日

    AHKManager.ahk  AHK管理器  2019年12月15日 快捷键   {Alt} + {F1} ///////////////////////////////////////////// ...

  7. 34.ITerm配置使用——2019年12月24日

    2019年12月23日15:17:36 ITerm使用教程 1.快键键配置 设置方法 设置方法如下: (1)选择 Preference 进入偏好设置: (2)选择 Profiles > Keys ...

  8. 35.ES6语法介绍——2019年12月24日

    2019年12月24日16:22:24 2019年10月09日12:04:44 1. ES6介绍 1.1 新的 Javascript 语法标准 --2015年6月正式发布 --使用babel语法转换器 ...

  9. 18.Vim基础指令(自用)——2019年12月13日

    title: vim study date: "2018-12-26 20:17:16" tags: 指令学习 categories: 技术驿站 vim study 2018年12 ...

随机推荐

  1. canvas介绍(画布)

    canvas(画布)主要是位图 svg(矢量图) canvas标签,必须要写的3个属性 id width height 为什么不再style中设置width和height呢? 因为这设置width和h ...

  2. apache cgi 程序: End of script output before headers

    测试linux Apache cgi程序: #include <stdio.h> int main(){ printf("abc"); ; } 目录:/var/www/ ...

  3. java虚拟机规范-运行时数据区

    前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 数据类型 java总共有两种数据类型:基本类型和引用类型.java虚拟机 ...

  4. Java操作数据库之JDBC增删改查

    1.java连接MySql数据库 代码区域: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ...

  5. 移动端调试 — iPhone +Safari

    1   开启iOS设备的调试功能 打开“设置”程序,进入“Safari”->“高级”页面开启“Web检查器”: 2   mac safari浏览器设置开发者工具 safari ->偏好设置 ...

  6. 【C++进阶:STL常见性质2】

    一般STL函数接收迭代器参数的规则为:[it1, it2) 左闭右开区间: vector<int> scores; scores.erase(scores.begin(),scores.e ...

  7. AtomicBoolean 源码分析

    AtomicBoolean AtomicBoolean 能解决什么问题?什么时候使用 AtomicBoolean? 可原子更新的 boolean 值 1)原子性:在Java中,对基本数据类型变量的读取 ...

  8. VMware 虚拟化编程(5) — VixDiskLib 虚拟磁盘库详解之一

    目录 目录 前文列表 VixDiskLib 虚拟磁盘库 虚拟磁盘数据的传输方式 Transport Methods VixDiskLib_ListTransportModes 枚举支持的传输模式 Vi ...

  9. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_05 IO字符流_5_flush方法和close方法的区别

    flush之后,还可以继续使用流写文件

  10. ClientDataSet初步使用

    https://blog.csdn.net/onebigday/article/details/5602619 ClientDataSet初步使用 2010年05月18日 08:36:00 阅读数:5 ...