go标准库的学习-time
参考https://studygolang.com/pkgdoc
导入形式:
import "time"
time包提供了时间的显示和测量用的函数。日历的计算采用的是公历。
1》时间点Time
type Time
type Time struct {
wall uint64
ext int64
loc *Location
}
Time代表一个纳秒精度的时间点。
Time零值代表时间点January 1, year 1, 00:00:00.000000000 UTC。因为本时间点一般不会出现在使用中,IsZero方法提供了检验时间是否显式初始化的一个简单途径。
每一个时间都具有一个地点信息(及对应地点的时区信息),当计算时间的表示格式时,如Format、Hour和Year等方法,都会考虑该信息。Local、UTC和In方法返回一个指定时区(但指向同一时间点)的Time。修改地点/时区信息只是会改变其表示;不会修改被表示的时间点,因此也不会影响其计算。
func (Time) String
func (t Time) String() string
String返回采用如下格式字符串的格式化时间。
"2006-01-02 15:04:05.999999999 -0700 MST"
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700" // 使用数字表示时区的RFC822
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // 使用数字表示时区的RFC1123
RFC3339 = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen = "3:04PM"
// 方便的时间戳
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
)
这些预定义的版式用于time.Format和time.Parse函数。用在版式中的参考时间是:
Mon Jan :: MST
对应的Unix时间是1136239445
1)举例如何使用在time.Format函数中:
func Now
func Now() Time
Now返回当前本地时间。
func (Time) Format
func (t Time) Format(layout string) string
Format根据layout指定的格式返回t代表的时间点的格式化文本表示,即将时间转换成想要的格式,layout定义了参考时间
package main
import(
"fmt"
"time"
) func main() {
fmt.Println(time.Now().Format(time.UnixDate)) //Tue Feb 12 12:10:21 CST 2019
fmt.Println(time.Now().Format(time.RFC3339Nano)) //2019-02-12T12:10:21.880328+08:00
fmt.Println(time.Now().Format(time.StampMicro)) //Feb 12 12:10:21.880337
//自定义格式
fmt.Println(time.Now().Format("2006-01-02 15:04:05")) //2019-02-12 12:10:21
fmt.Println(time.Now().Format("Jan 2, 2006 at 3:04pm (MST)")) //Feb 12, 2019 at 12:10pm (CST)
fmt.Println(time.Now().Format("2006-Jan-02")) //2019-Feb-12
}
2)如何使用在time.Parse函数中,上面例子的逆向:
func Parse
func Parse(layout, value string) (Time, error)
Parse解析一个格式化的时间字符串并返回它代表的时间。layout定义了参考的时间格式
package main
import(
"fmt"
"time"
) func main() {
unix, _ := time.Parse(time.UnixDate, "Tue Feb 12 12:10:21 CST 2019")
fmt.Println(unix) //2019-02-12 12:10:21 +0800 CST rfc, _ := time.Parse(time.RFC3339Nano, "2019-02-12T12:10:21.880328+08:00")
fmt.Println(rfc) //2019-02-12 12:10:21.880328 +0800 CST stamp, _ := time.Parse(time.StampMicro, "Feb 12 12:10:21.880337")
fmt.Println(stamp) //0000-02-12 12:10:21.880337 +0000 UTC custom1Form := "2006-01-02 15:04:05"
custom1, _ := time.Parse(custom1Form, "2019-02-12 12:10:21")
fmt.Println(custom1) //2019-02-12 12:10:21 +0000 UTC custom2Form := "Jan 2, 2006 at 3:04pm (MST)"
custom2, _ := time.Parse(custom2Form, "Feb 12, 2019 at 12:10pm (CST)")
fmt.Println(custom2) //2019-02-12 12:10:00 +0800 CST custom3Form := "2006-Jan-02"
custom3, _ := time.Parse(custom3Form, "2019-Feb-12")
fmt.Println(custom3) //2019-02-12 00:00:00 +0000 UTC
}
数字表示的时区格式如下:
- ±hhmm
-: ±hh:mm
将格式字符串中的负号替换为Z会触发ISO 8601行为(当时区是UTC时,输出Z而不是时区偏移量),这样:
Z0700 Z or ±hhmm
Z07: Z or ±hh:mm
其他的获取Time对象的方法:
首先先说明时区Location
type Location
type Location struct {
name string
zone []zone
tx []zoneTrans
cacheStart int64
cacheEnd int64
cacheZone *zone
}
Location代表一个(关联到某个时间点的)地点,以及该地点所在的时区。
var Local *Location = &localLoc
Local代表系统本地,对应本地时区,通过time.Local来使用。
var UTC *Location = &utcLoc
UTC代表通用协调时间,对应零时区,通过time.UTC来使用。
3)
func LoadLocation
func LoadLocation(name string) (*Location, error)
LoadLocation返回使用给定的名字创建的Location,即时区。
如果name是""或"UTC",返回UTC;如果name是"Local",返回Local;否则name应该是IANA时区数据库里有记录的地点名(该数据库记录了地点和对应的时区),如"America/New_York"。
LoadLocation函数需要的时区数据库可能不是所有系统都提供,特别是非Unix系统。此时LoadLocation会查找环境变量ZONEINFO指定目录或解压该变量指定的zip文件(如果有该环境变量);然后查找Unix系统的惯例时区数据安装位置,最后查找$GOROOT/lib/time/zoneinfo.zip。
func (Time) In
func (t Time) In(loc *Location) Time
In返回采用loc指定的地点和时区,但指向同一时间点的Time。如果loc为nil会panic。
package main
import(
"fmt"
"time"
) func main() {
loc, _ := time.LoadLocation("America/Los_Angeles") //美国洛杉矶时区PST
fmt.Println(loc) //America/Los_Angeles
fmt.Println(time.Now()) //2019-02-12 15:03:12.649876 +0800 CST m=+0.000715568,相对于UTC时区正向差8小时
fmt.Println(time.Now().In(loc)) //2019-02-11 23:03:12.649952 -0800 PST,相对于UTC时区正向差8小时,因此loc时区和本地时区相差16小时
}
4)
func ParseInLocation
func ParseInLocation(layout, value string, loc *Location) (Time, error)
ParseInLocation类似Parse但有两个重要的不同之处。第一,当缺少时区信息时,Parse将时间解释为UTC时间,而ParseInLocation将返回值的Location设置为loc;第二,当时间字符串提供了时区偏移量信息时,Parse会尝试去匹配本地时区,而ParseInLocation会去匹配loc。
举例:
package main
import(
"fmt"
"time"
) func main() {
loc, _ := time.LoadLocation("America/Los_Angeles")
custom2Form := "2006-01-02 15:04:05"
custom2, _ := time.ParseInLocation(custom2Form, "2019-02-12 12:10:21", loc)
fmt.Println(custom2) //2019-02-12 12:10:21 -0800 PST,可见将时区设置为了指定的loc时区
custom2Parse, _ := time.Parse(custom2Form, "2019-02-12 12:10:21")
fmt.Println(custom2Parse) //2019-02-12 12:10:21 +0000 UTC,可见如果没有设置时区则默认为UTC时区
}
5)
func Unix
func Unix(sec int64, nsec int64) Time
Unix创建一个本地时间,对应sec和nsec表示的Unix时间(从January 1, 1970 UTC至该时间的秒数和纳秒数)。
nsec的值在[0, 999999999]范围外是合法的。
获得时间的时间戳
func (Time) Unix
func (t Time) Unix() int64
Unix将t表示为Unix时间,即从时间点January 1, 1970 UTC到时间点t所经过的时间(单位秒)。
func (Time) UnixNano
func (t Time) UnixNano() int64
UnixNano将t表示为Unix时间,即从时间点January 1, 1970 UTC到时间点t所经过的时间(单位纳秒)。如果纳秒为单位的unix时间超出了int64能表示的范围,结果是未定义的。注意这就意味着Time零值调用UnixNano方法的话,结果是未定义的。
举例:
package main
import(
"fmt"
"time"
) func main() {
fmt.Println(time.Now().Unix()) //
fmt.Println(time.Now().UnixNano()) //1549956211529784000
fmt.Println(time.Unix(1549956211, 529784000)) //2019-02-12 15:23:31.529784 +0800 CST
}
然后使用上面例子得到的秒数或纳秒数来调用Unix得到Time对象:
package main
import(
"fmt"
"time"
) func main() {
fmt.Println(time.Unix(, )) //2019-02-12 15:23:31 +0800 CST
fmt.Println(time.Unix(, )) //2019-02-12 15:23:31.529784 +0800 CST
}
6)
func Date
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
Date返回一个时区为loc、当地时间为:
year-month-day hour:min:sec + nsec nanoseconds
的时间点。
month、day、hour、min、sec和nsec的值可能会超出它们的正常范围,在转换前函数会自动将之规范化。如October 32被修正为November 1。
举例:
package main
import(
"fmt"
"time"
) func main() {
fmt.Println(time.Unix(, )) //2019-02-12 15:23:31.529784 +0800 CST
//等价于上面的Unix方法
t := time.Date(, time.February, , , , , , time.Local)
fmt.Println(t)////2019-02-12 15:23:31.529784 +0800 CST
}
当你得到了Time对象后,你就能够调用相应的函数来获得相应的信息,选择其中几个说明,其他省略:
func (Time) Round
func (t Time) Round(d Duration) Time
返回距离t最近的时间点,得到的是晚于t的时间,该时间点应该满足从Time零值到该时间点的时间段能整除d;如果有两个满足要求的时间点,距离t相同,会向上舍入;如果d <= 0,会返回t的拷贝。
举例:
package main
import(
"fmt"
"time"
) func main() {
t := time.Date(, time.February, , , , , , time.Local)
fmt.Println(t)////2019-02-12 15:23:31.529784 +0800 CST round := []time.Duration{
time.Nanosecond, //按纳秒四舍五入,9位
time.Microsecond, //按微秒,6位
time.Millisecond, //按毫秒,3位,0省略
time.Second, //按秒
* time.Second, //按2秒
time.Minute, //按分
* time.Minute, //按10分
time.Hour, //按小时
}
for _, d := range round {
fmt.Printf("t.Round(%6s) = %s\n", d, t.Round(d).Format("15:04:05.999999999"))
}
}
返回:
userdeMBP:go-learning user$ go run test.go
-- ::31.529784 + CST
t.Round( 1ns) = ::31.529784
t.Round( 1µs) = ::31.529784
t.Round( 1ms) = ::31.53 //四舍五入为530
t.Round( 1s) = ::32 //四舍五入为32
t.Round( 2s) = ::
t.Round( 1m0s) = ::
t.Round( 10m0s) = ::
t.Round(1h0m0s) = ::
func (Time) Truncate
func (t Time) Truncate(d Duration) Time
类似Round,但是返回的是最接近但早于t的时间点;如果d <= 0,会返回t的拷贝。
可见同样的值使用Truncate得到的结果和Round是不同的
举例:
package main
import(
"fmt"
"time"
) func main() {
t := time.Date(, time.February, , , , , , time.Local)
fmt.Println(t)////2019-02-12 15:23:31.529784 +0800 CST round := []time.Duration{
time.Nanosecond, //按纳秒四舍五入,9位
time.Microsecond, //按微秒,6位
time.Millisecond, //按毫秒,3位,0省略
time.Second, //按秒
* time.Second, //按2秒
time.Minute, //按分
* time.Minute, //按10分
time.Hour, //按小时
}
for _, d := range round {
fmt.Printf("t.Round(%6s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
}
}
返回:
userdeMBP:go-learning user$ go run test.go
-- ::31.529784 + CST
t.Round( 1ns) = ::31.529784
t.Round( 1µs) = ::31.529784
t.Round( 1ms) = ::31.529
t.Round( 1s) = ::
t.Round( 2s) = ::
t.Round( 1m0s) = ::
t.Round( 10m0s) = ::
t.Round(1h0m0s) = ::
有关Duration的内容向下看
2》
type Weekday
type Weekday int
Weekday代表一周的某一天。
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
func (Weekday) String
func (d Weekday) String() string
String返回该日(周几)的英文名("Sunday"、"Monday",……)
func (Time) Weekday
func (t Time) Weekday() Weekday
返回时间点t对应的那一周的周几。
type Month
type Month int
Month代表一年的某个月。
const (
January Month = + iota
February
March
April
May
June
July
August
September
October
November
December
)
func (Month) String
func (m Month) String() string
String返回月份的英文名("January","February",……)
举例:
package main
import(
"fmt"
"time"
) func main() {
fmt.Println(time.Now().Weekday()) //默认调用func (Weekday) String()函数,返回Tuesday
fmt.Println(time.Now().Month()) //默认调用func (Month) String()函数,返回February
}
3》时间段Duration
type Duration
type Duration int64
Duration类型代表两个时间点之间经过的时间,以纳秒为单位。可表示的最长时间段大约290年。
const (
Nanosecond Duration =
Microsecond = * Nanosecond
Millisecond = * Microsecond
Second = * Millisecond
Minute = * Second
Hour = * Minute
)
常用的时间段。没有定义一天或超过一天的单元,以避免夏时制的时区切换的混乱。
要将Duration类型值表示为某时间单元的个数,用除法:
second := time.Second
fmt.Print(int64(second/time.Millisecond)) // prints 1000
要将整数个某时间单元表示为Duration类型值,用乘法:
seconds :=
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
func ParseDuration
func ParseDuration(s string) (Duration, error)
ParseDuration解析一个时间段字符串。一个时间段字符串是一个序列,每个片段包含可选的正负号、十进制数、可选的小数部分和单位后缀,如"300ms"、"-1.5h"、"2h45m"。合法的单位有"ns"、"us" /"µs"、"ms"、"s"、"m"、"h"。
举例:
package main
import(
"fmt"
"time"
) func main() {
dur1, _ := time.ParseDuration("1.5s")//1.5s
dur2, _ := time.ParseDuration("2h45m") //2h45m0s
dur3, _ := time.ParseDuration("-1.5h") //-1h30m0s
fmt.Println(dur1)
fmt.Println(dur2)
fmt.Println(dur3)
}
func Since
func Since(t Time) Duration
Since返回从t到现在经过的时间,等价于time.Now().Sub(t)。
举例:
package main
import(
"fmt"
"time"
) func main() {
t := time.Date(, time.February, , , , , , time.Local)
fmt.Println(t)//2019-02-12 15:23:31.529784 +0800 CST
fmt.Println(time.Since(t))//50m31.878043s,现在据上面的时间已经过了50分钟31秒
}
func (Duration) String
func (d Duration) String() string
返回时间段采用"72h3m0.5s"格式的字符串表示。最前面可以有符号,数字+单位为一个单元,开始部分的0值单元会被省略;如果时间段<1s,会使用"ms"、"us"、"ns"来保证第一个单元的数字不是0;如果时间段为0,会返回"0"。
4》用于时间运算
来自https://blog.csdn.net/wschq/article/details/80114036
// func Sleep(d Duration) 休眠多少时间,休眠时处于阻塞状态,后续程序无法执行
time.Sleep(time.Duration() * time.Second) // func After(d Duration) <-chan Time 非阻塞,可用于延迟
time.After(time.Duration() * time.Second)
//select { case m := <-c: handle(m) case <-time.After(5 * time.Minute): fmt.Println("timed out") }
// func Since(t Time) Duration 两个时间点的间隔
start := time.Now()
fmt.Println(time.Since(start)) // 等价于 Now().Sub(t), 可用来计算一段业务的消耗时间 func Until(t Time) Duration // 等价于 t.Sub(Now()),t与当前时间的间隔 // func (t Time) Add(d Duration) Time
fmt.Println(dt.Add(time.Duration() * time.Second)) // 加 func (t Time) Sub(u Time) Duration // 减 // func (t Time) AddDate(years int, months int, days int) Time
fmt.Println(dt.AddDate(, , )) // func (t Time) Before(u Time) bool
// func (t Time) After(u Time) bool
// func (t Time) Equal(u Time) bool 比较时间点时尽量使用Equal函数
5》定点计时
计时器(Timer)的原理和倒计时闹钟类似,都是给定多少时间后触发。
打点器(Ticker)的原理和钟表类似,钟表每到整点就会触发。
这两种方法创建后会返回 time.Ticker 对象和 time.Timer 对象,里面通过一个 C 成员,类型是只能接收的时间通道(<-chan Time),使用这个通道就可以获得时间触发的通知。
1)type Timer
type Timer struct {
C <-chan Time
// 内含隐藏或非导出字段
}
Timer类型代表单次时间事件。当Timer到期时,当时的时间会被发送给C,除非Timer是被AfterFunc函数创建的。
创建Timer的两种方法:
1.func NewTimer
func NewTimer(d Duration) *Timer
NewTimer创建一个Timer,它会在最少过去时间段d后到期,向其自身的C字段发送当时的时间。
2.func AfterFunc
func AfterFunc(d Duration, f func()) *Timer
AfterFunc另起一个go程等待时间段d过去,然后调用f。它返回一个Timer,可以通过调用其Stop方法来取消等待和对f的调用。
使用time.AfterFunc()实现等待一段时间后调用函数,并直到该函数生成的另一goroutine结束后才结束main()函数的goroutine
package main
import(
"fmt"
"time"
) func main() {
//声明一个用于退出的通道
exit := make(chan int) fmt.Println("start")
//过1秒后,就会开一个新goroutine来运行匿名函数
time.AfterFunc(time.Second, func(){
//该匿名函数的作用就是在1秒后打印结果,并通知main()函数可以结束主goroutine
fmt.Println("one second after")
exit <- 0
}) //main()正在等待从exit通道中接受数据来结束主goroutine
<- exit
}
返回:
userdeMBP:go-learning user$ go run test.go
start
one second after
⚠️以上两函数都可以使用 Reset:
func (*Timer) Reset
func (t *Timer) Reset(d Duration) bool
Reset使t重新开始计时,(本方法返回后再)等待时间段d过去后到期。如果调用时t还在等待中会返回真;如果t已经到期或者被停止了会返回假。
这个有个需要注意的地方是使用 Reset
时需要确保 t.C
通道被释放时才能调用,以防止发生资源竞争的问题,可通过以下方式解决:
if !t.Stop() {//如果t已经被停止或者过期了,则先将t.C
通道释放,然后才调用Reset来重新计时,否则此时通道是满的,导致资源竞争
<-t.C
}
t.Reset(d)
func (*Timer) Stop
func (t *Timer) Stop() bool
Stop停止Timer的执行。如果还没停止并停止了t会返回真;如果t已经被停止或者过期了会返回假。Stop不会关闭通道t.C,以避免从该通道的读取不正确的成功。
2)type Ticker
type Ticker struct {
C <-chan Time // 周期性传递时间信息的通道
// 内含隐藏或非导出字段
}
Ticker保管一个通道,并每隔一段时间向其传递"tick"。
func NewTicker
func NewTicker(d Duration) *Ticker
NewTicker返回一个新的Ticker,该Ticker包含一个通道字段,并会每隔时间段d就向该通道发送当时的时间。它会调整时间间隔或者丢弃tick信息以适应反应慢的接收者。如果d<=0会panic。关闭该Ticker可以释放相关资源。
举例:
下面代码创建一个打点器Ticker,每 500 毫秒触发一起;创建一个计时器Timer,2 秒后触发,只触发一次。
package main
import(
"fmt"
"time"
) func main() {
//创建一个打点器,每500毫秒触发一次
ticker := time.NewTicker(time.Millisecond * 500) //创建一个计时器,2秒后触发
timer := time.NewTimer(time.Second * 2) //声明计数变量
var count int //不断检查通道情况
for{
//多路复用通道
select{
case <- timer.C://计时器到时了,即2秒已到
fmt.Println("time is over,stop!!")
goto StopLoop
case <- ticker.C://打点器触发了,说明已隔500毫秒
count++
fmt.Println("tick : ", count)
}
} //停止循环所到的标签
StopLoop:
fmt.Println("ending")
}
返回:
userdeMBP:go-learning user$ go run test.go
tick : 1
tick : 2
tick : 3
tick : 4
time is over,stop!!
ending
func (*Ticker) Stop
func (t *Ticker) Stop()
Stop关闭一个Ticker。在关闭后,将不会发送更多的tick信息。Stop不会关闭通道t.C,以避免从该通道的读取不正确的成功。
go标准库的学习-time的更多相关文章
- go标准库的学习-net/http
参考:https://studygolang.com/pkgdoc 概念解释: request:用户请求的信息,用来解析用户的请求信息,包括post.get.cookie.url等信息 respons ...
- go标准库的学习-database/sql
参考:https://studygolang.com/pkgdoc 导入方式: import "database/sql" sql包提供了保证SQL或类SQL数据库的泛用接口. 使 ...
- go标准库的学习-crypto/md5
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/md5" md5包实现了MD5哈希算法,参见RFC 1321. Con ...
- go标准库的学习-crypto/sha1
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha1" sha1包实现了SHA1哈希算法,参见RFC 3174. ...
- go标准库的学习-crypto/sha256
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha256" sha256包实现了SHA224和SHA256哈希算法 ...
- python 标准库基础学习之开发工具部分1学习
#2个标准库模块放一起学习,这样减少占用地方和空间#标准库之compileall字节编译源文件import compileall,re,sys#作用是查找到python文件,并把它们编译成字节码表示, ...
- python calendar标准库基础学习
# -*- coding: utf-8 -*-# 作者:新手__author__ = 'Administrator'#标准库:日期时间基础学习:calendar:处理日期#例1import calen ...
- 《C标准库》学习笔记整理
简介 <C标准库>书中对 C 标准库中的 15 个头文件的内容进行了详细的介绍,包括各头文件设计的背景知识.头文件中的内容.头文件中定义的函数和变量的使用.实现.测试等. 我学习此书的目的 ...
- python linecache标准库基础学习
#python标准库基础之:linecacge:高效读取文本文件#说明与作用"""可以从文件或者导入python模块获取文件,维护一个结果缓存,从而可以更高效地从相同文件 ...
- python StringIO标准库基础学习
#标准库:StringIO提供类文件API文本缓冲区#作用:可以处理内存中的文本,有2种不同的实现:cStringIP版本用c编写提高速度,StringIO用python来提供可移植性,与其他字符串连 ...
随机推荐
- c#中打开Excel文档
方法一:(调用Excel的COM组件) 在项目中打开Add Reference对话框,选择COM栏,之后在COM列表中找到"Microsoft Excel 11.0 Object ...
- 用Visual Studio Code写Node.j
介绍 vsc的宣传语是: 一个运行于 Mac OS X.Windows和 Linux 之上的,针对于编写现代 Web 和云应用的跨平台源代码编辑器. 按它说的,vsc特别适合来作为前端开发编辑器. 内 ...
- 《Photoshop CS4手绘艺术技法》
书名 <Photoshop CS4手绘艺术技法> 图片 时间 2017-4月 学习 想了想当初的学习动机,自己P图片可是P的是实在是丑就会做几张动图.看完了才发现这行博大精深而且自己的审 ...
- Vue动态新增对象属性
Vue.set( target, key, value ) 参数: {Object | Array} target {string | number} key {any} value 返回值:设置的值 ...
- 如何使tinymce编辑器的高度随内容自变化(转载)
如何使tinymce编辑器的高度随内容自变化 最简单的方法就是在配置时添加Autoresize插件: tinymce.init({ selector: "textarea", // ...
- Matlab Euler's method
% matlab script to test efficiency of % Euler's method, classical Runge-Kutta, and ode45 % on Arenst ...
- 设计模式之观察者模式(Observer)
观察者模式通常的叫法叫做订阅-发布模式,类似于报刊杂志的订阅,观察者和被观察者就是读者和邮局的关系,读者先要在邮局订阅想要的报刊,当报刊发行时,邮局会将报刊邮寄到读者家里.观察者(Observer)和 ...
- Mybatis逆向工程生成po、mapper接口、mapper.xml
Mybatis逆向工程生成po.mapper接口.mapper.xml 一.新建一个maven工程 请查看我的另一篇博客:<使用idea创建一个maven工程> 二.引入所需依赖 需要my ...
- js 动态绑定事件 on click 完美解决绑定不成功
动态绑定坑了多少人..... //绑定 $("ol").on("click","li a",function(){ ... }) / ...
- 洛谷P4007 小 Y 和恐怖的奴隶主(期望dp 矩阵乘法)
题意 题目链接 Sol 首先不难想到一种暴力dp,设\(f[i][a][b][c]\)表示还有\(i\)轮没打,场上有\(a\)个1血,\(b\)个2血,\(c\)个三血 发现状态数只有\(s = 1 ...