了解标准库是一个非常好的学习语言的方法。接下里的一些章节我们将详细研究标准库中的类型,方法,结合实际应用案例进行有趣的编程。
字符串处理是比较基础的库,我们从简单的库开始入门。
本节我们将继续用实例代码研究以下函数的用法。
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Print(strings.Trim("¡¡¡Hello, Gophers!!!", "!¡")) // Hello, Gophers
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
fmt.Print(strings.TrimFunc("¡¡¡Hello, Gophers!!!", func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
}))// Hello, Gophers
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Print(strings.TrimLeft("¡¡¡Hello, Gophers!!!", "!¡")) // Hello, Gophers!!!
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
fmt.Print(strings.TrimLeftFunc("¡¡¡Hello, Gophers!!!", func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})) // Hello, Gophers!!!
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.TrimPrefix("¡¡¡Hello, Gophers!!!", "¡")) // ¡¡Hello, Gophers!!!
fmt.Println(strings.TrimPrefix("¡¡¡Hello, Gophers!!!", "¡¡¡Hello, ")) // Gophers!!!
fmt.Println(strings.TrimPrefix("¡¡¡Hello, Gophers!!!", "¡¡¡Howdy, ")) // ¡¡¡Hello, Gophers!!!
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Print(strings.TrimRight("¡¡¡Hello, Gophers!!!", "!¡")) // ¡¡¡Hello, Gophers
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
fmt.Print(strings.TrimRightFunc("¡¡¡Hello, Gophers!!!", func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
}))
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.TrimSpace(" \t\n Hello, Gophers \n\t\r\n")) // Hello, Gophers
}
package main
import (
"fmt"
"strings"
)
func main() {
var s = "¡¡¡Hello, Gophers!!!"
s = strings.TrimSuffix(s, ", Gophers!!!")
s = strings.TrimSuffix(s, ", Marmots!!!")
fmt.Print(s) // ¡¡¡Hello
}
了解标准库是一个非常好的学习语言的方法。接下里的一些章节我们将详细研究标准库中的类型,方法,结合实际应用案例进行有趣的编程。
字符串处理是比较基础的库,我们从简单的库开始入门。
本节我们将继续用实例代码研究以下函数的用法。
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.ToLower("Gopher")) // gopher
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
fmt.Println(strings.ToLowerSpecial(unicode.TurkishCase, "Önnek İş")) // önnek iş
}
package main
import (
"fmt"
"strings"
)
func main() {
// Compare this example to the Title example.
fmt.Println(strings.ToTitle("her royal highness")) // HER ROYAL HIGHNESS
fmt.Println(strings.ToTitle("loud noises")) // LOUD NOISES
fmt.Println(strings.ToTitle("хлеб")) // ХЛЕБ
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
fmt.Println(strings.ToTitleSpecial(unicode.TurkishCase, "dünyanın ilk borsa yapısı Aizonai kabul edilir"))
// DÜNYANIN İLK BORSA YAPISI AİZONAİ KABUL EDİLİR
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.ToUpper("Gopher"))
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
fmt.Println(strings.ToUpperSpecial(unicode.TurkishCase, "örnek iş")) // ÖRNEK İŞ
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%s\n", strings.ToValidUTF8("abc", "\uFFFD")) // abc
fmt.Printf("%s\n", strings.ToValidUTF8("a\xffb\xC0\xAFc\xff", "")) // abc
fmt.Printf("%s\n", strings.ToValidUTF8("\xed\xa0\x80", "abc")) // abc
}
了解标准库是一个非常好的学习语言的方法。接下里的一些章节我们将详细研究标准库中的类型,方法,结合实际应用案例进行有趣的编程。
字符串处理是比较基础的库,我们从简单的库开始入门。
本节我们将继续用实例代码研究以下函数的用法。
package main
import (
"fmt"
"strings"
)
func main() {
s := []string{"foo", "bar", "baz"}
fmt.Println(strings.Join(s, ", ")) // foo, bar, baz
}
import (
"fmt"
"strings"
)
func main() {
rot13 := func(r rune) rune {
switch {
case r >= 'A' && r <= 'Z':
return 'A' + (r-'A'+13)%26
case r >= 'a' && r <= 'z':
return 'a' + (r-'a'+13)%26
}
return r
}
fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher...")) // 'Gjnf oevyyvt naq gur fyvgul tbcure...
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println("ba" + strings.Repeat("na", 2)) // banana
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.Replace("oink oink oink", "", "###", 1))
fmt.Println(strings.Replace("oink oink oink", "", "###", 2))
fmt.Println(strings.Replace("oink oink oink", "", "###", -1))
fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
}
输出:
###oink oink oink
###o###ink oink oink
###o###i###n###k### ###o###i###n###k### ###o###i###n###k###
oinky oinky oink
moo moo moo
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.ReplaceAll("oink oink oink", "oink", "moo")) // moo moo moo
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
fmt.Printf("%q\n", strings.Split(" xyz ", ""))
fmt.Printf("%q\n", strings.Split("", ""))
fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
}
输出:
["a" "b" "c"]
["" "man " "plan " "canal panama"]
[" " "x" "y" "z" " "]
[]
[""]
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ",")) // ["a," "b," "c"]
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2)) // ["a," "b,c"]
fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 0)) // []
fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 5)) // ["a," "b," "c"]
fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", -1)) // ["a," "b," "c"]
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2)) // ["a" "b,c"]
z := strings.SplitN("a,b,c", ",", 0)
fmt.Printf("%q (nil = %v)\n", z, z == nil) // [] (nil = true)
}
了解标准库是一个非常好的学习语言的方法。接下里的一些章节我们将详细研究标准库中的类型,方法,结合实际应用案例进行有趣的编程。
字符串处理是比较基础的库,我们从简单的库开始入门。
本节我们将继续用实例代码研究以下函数的用法。
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.Index("chicken", "ken")) // 4
fmt.Println(strings.Index("chicken", "dmr")) // -1
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.IndexAny("chicken", "aeiouy")) // 2
fmt.Println(strings.IndexAny("crwth", "aeiouy")) // -1
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.IndexByte("golang", 'g')) // 0
fmt.Println(strings.IndexByte("gophers", 'h')) // 3
fmt.Println(strings.IndexByte("golang", 'x')) // -1
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
f := func(c rune) bool {
return unicode.Is(unicode.Han, c)
}
fmt.Println(strings.IndexFunc("Hello, 世界", f)) // 7
fmt.Println(strings.IndexFunc("Hello, world", f)) // -1
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.IndexRune("chicken", 'k')) // 4
fmt.Println(strings.IndexRune("chicken", 'd')) // -1
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.Index("go gopher", "go")) // 0
fmt.Println(strings.LastIndex("go gopher", "go")) // 3
fmt.Println(strings.LastIndex("go gopher", "rodent")) // -1
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.LastIndexAny("go gopher", "go")) // 4
fmt.Println(strings.LastIndexAny("go gopher", "rodent")) // 8
fmt.Println(strings.LastIndexAny("go gopher", "fail")) // -1
}
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.LastIndexByte("Hello, world", 'l')) // 10
fmt.Println(strings.LastIndexByte("Hello, world", 'o')) // 8
fmt.Println(strings.LastIndexByte("Hello, world", 'x')) // -1
}
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
fmt.Println(strings.LastIndexFunc("go 123", unicode.IsNumber)) // 5
fmt.Println(strings.LastIndexFunc("123 go", unicode.IsNumber)) // 2
fmt.Println(strings.LastIndexFunc("go", unicode.IsNumber)) // -1
}
了解标准库是一个非常好的学习语言的方法。接下里的一些章节我们将详细研究标准库中的类型,方法,结合实际应用案例进行有趣的编程。
字符串处理是比较基础的库,我们从简单的库开始入门。
本节我们将继续用实例代码研究以下函数的用法。
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
m := "hello this is strings."
// cut用sep参数分割原字符串,返回3个参数,切割后左边部分,切割后右边部分,是否存在sep,不存在就不切割
show := func(s, sep string) {
before, after, found := strings.Cut(s, sep)
fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
}
show(m, "this")
show(m, "is")
show(m, "wow")
// cutprefix用于去掉前缀,如果原字符串以sep开头就去掉这一部分,返回剩余部分,以及是否存在布尔值
show2 := func(s, sep string) {
after, found := strings.CutPrefix(s, sep)
fmt.Printf("CutPrefix(%q, %q) = %q, %v\n", s, sep, after, found)
}
show2(m, "hello")
show2(m, "this")
show2(m, "wow")
// cutsuffix用于去掉后缀,如果原字符串以sep结尾就去掉这一部分,返回剩余部分,以及是否存在布尔值
show3 := func(s, sep string) {
after, found := strings.CutSuffix(s, sep)
fmt.Printf("CutSuffix(%q, %q) = %q, %v\n", s, sep, after, found)
}
show3(m, "strings")
show3(m, "strings.")
show3(m, "wow")
// equalFold是否在utf8编码下,不区分大小写相等
fmt.Println("Go equalFold go?", strings.EqualFold("Go", "go"))
// fields用空白字符分割字符串,包括空格,多个空格,\t,\r,\n
fmt.Println("Fields are 1: ", strings.Fields(" foo bar baz "))
fmt.Println("Fields are 2: ", strings.Fields(" foo bar\t baz "))
fmt.Println("Fields are 3: ", strings.Fields(" foo bar\r\nbaz "))
// fieldsFunc根据提供的函数分割字符串,下面的f函数判断当c不是字母也不是数字的时候返回true,也就是在此处分割
f := func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
}
fmt.Println("Fields are 4: ", strings.FieldsFunc(" foo1;bar2,baz3...", f))
// hasPrefix, 区分大小写
fmt.Println(strings.HasPrefix(m, "Hello"))
// hasSuffix, 区分大小写
fmt.Println(strings.HasSuffix(m, "strings."))
}
输出:
Cut("hello this is strings.", "this") = "hello ", " is strings.", true
Cut("hello this is strings.", "is") = "hello th", " is strings.", true
Cut("hello this is strings.", "wow") = "hello this is strings.", "", false
CutPrefix("hello this is strings.", "hello") = " this is strings.", true
CutPrefix("hello this is strings.", "this") = "hello this is strings.", false
CutPrefix("hello this is strings.", "wow") = "hello this is strings.", false
CutSuffix("hello this is strings.", "strings") = "hello this is strings.", false
CutSuffix("hello this is strings.", "strings.") = "hello this is ", true
CutSuffix("hello this is strings.", "wow") = "hello this is strings.", false
Go equalFold go? true
Fields are 1: [foo bar baz]
Fields are 2: [foo bar baz]
Fields are 3: [foo bar baz]
Fields are 4: [foo1 bar2 baz3]
false
false
了解标准库是一个非常好的学习语言的方法。接下里的一些列章节我们将详细研究标准库中的类型,方法,结合实际应用案例进行有趣的编程。
字符串处理是比较基础的库,我们从简单的库开始入门。
先看一下strings相关的类型和方法,大概分为通用方法部分和Builder,Reader,Replacer类型。
package main
import (
"fmt"
"strings"
"unsafe"
)
func main() {
m := "hello this is strings."
c := strings.Clone(m)
// 判断相同指针,clone会创建新副本,因此这里返回false
fmt.Println(unsafe.StringData(c) == unsafe.StringData(m))
// 比较,返回0则相等
fmt.Println(strings.Compare(c, m))
// 是否包含hello字符串
fmt.Println(strings.Contains(c, "hello"))
// 是否含有xyzh中的任意一个字母
fmt.Println(strings.ContainsAny(c, "xyzh"))
// 是否有z字母
fmt.Println(strings.ContainsFunc(c, func(a rune) bool {
return a == 'z'
}))
// 是否有a字母
fmt.Println(strings.ContainsRune(c, 97))
// 字母i出现几次
fmt.Println(strings.Count(c, "i"))
}
false
0
true
true
false
false
3
切片排序或搜索功能允许您以各种方式与切片进行交互和操作。Golang排序函数是核心的一部分。使用此功能无需安装,只需导入"sort"包即可。借助排序功能,您可以搜索任何重要的Golang排序函数列表如下:
Ints函数按升序对整数切片进行排序。
func Ints(intSlice []int)
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
intSlice := []int{10, 5, 25, 351, 14, 9} // unsorted
fmt.Println("Slice of integer BEFORE sort:",intSlice)
sort.Ints(intSlice)
fmt.Println("Slice of integer AFTER sort:",intSlice)
}
输出:
Slice of integer BEFORE sort: [10 5 25 351 14 9]
Slice of integer AFTER sort: [5 9 10 14 25 351]
Strings函数按字典升序对字符串切片进行排序。
func Strings(strSlice []string)
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
strSlice := []string{"Jamaica","Estonia","Indonesia","Hong Kong"} // unsorted
fmt.Println("Slice of string BEFORE sort:",strSlice)
sort.Strings(strSlice)
fmt.Println("Slice of string AFTER sort:",strSlice)
fmt.Println("\n-----------------------------------\n")
strSlice = []string{"JAMAICA","Estonia","indonesia","hong Kong"} // unsorted
fmt.Println("Slice of string BEFORE sort:",strSlice)
sort.Strings(strSlice)
fmt.Println("Slice of string AFTER sort:",strSlice)
}
输出:
Slice of string BEFORE sort: [Jamaica Estonia Indonesia Hong Kong]
Slice of string AFTER sort: [Estonia Hong Kong Indonesia Jamaica]
-----------------------------------
Slice of string BEFORE sort: [JAMAICA Estonia indonesia hong Kong]
Slice of string AFTER sort: [Estonia JAMAICA hong Kong indonesia]
Float64s函数按升序对float64的切片进行排序。
func Float64s(fltSlice []string)
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
fltSlice := []float64{18787677.878716, 565435.321, 7888.545, 8787677.8716, 987654.252} // unsorted
fmt.Println("Slice BEFORE sort: ",fltSlice)
sort.Float64s(fltSlice)
fmt.Println("Slice AFTER sort: ",fltSlice)
}
输出:
Slice BEFORE sort: [1.8787677878716e+07 565435.321 7888.545 8.7876778716e+06 987654.252]
Slice AFTER sort: [7888.545 565435.321 987654.252 8.7876778716e+06 1.8787677878716e+07]
IntsAreSorted函数测试整数切片是否按升序排序。如果按升序找到数字切片,则返回true,否则返回false。
func IntsAreSorted(a []string) bool
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
intSlice := []int{10, 5, 25, 351, 14, 9} // unsorted
fmt.Println(sort.IntsAreSorted(intSlice)) // false
intSlice = []int{5, 9, 14, 351, 614, 999} // sorted
fmt.Println(sort.IntsAreSorted(intSlice)) // true
}
输出:
false
true
StringsAreSorted函数测试字符串切片是否按升序排序。如果按升序找到字符串切片,则返回true,否则返回false。
func StringsAreSorted(strSlice []string) bool
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
strSlice := []string{"Jamaica","Estonia","Indonesia","Hong Kong"} // unsorted
fmt.Println(sort.StringsAreSorted(strSlice)) // false
strSlice = []string{"JAMAICA","Estonia","indonesia","hong Kong"} // unsorted
fmt.Println(sort.StringsAreSorted(strSlice)) // false
strSlice = []string{"estonia","hong Kong","indonesia","jamaica"} // sorted
fmt.Println(sort.StringsAreSorted(strSlice)) // true
}
输出:
false
false
true
Float64sAreSorted函数测试float64s的切片是否按升序排序。如果按升序找到float64的切片,则返回true,否则返回false。
func Float64sAreSorted(fltSlice []float64) bool
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
fltSlice := []float64{18787677.878716, 565435.321, 7888.545, 8787677.8716, 987654.252} // unsorted
fmt.Println(sort.Float64sAreSorted(fltSlice)) // false
fltSlice = []float64{565435.321, 887888.545, 8787677.8716, 91187654.252} // sorted
fmt.Println(sort.Float64sAreSorted(fltSlice)) // true
}
输出:
false
true
SearchInts函数在int的排序切片中搜索x的位置,并返回Search指定的索引。如果切片仅按排序顺序排列,则此函数有效。如果在intSlice中找到x,则返回intSlice的索引位置,否则返回x适合排序切片的索引位置。以下示例显示了SearchInts() 函数的用法:
func SearchInts(intSlice []int, x int) int
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
// integer slice in unsort order
intSlice := []int{55, 22, 18, 9, 12, 82, 28, 36, 45, 65}
x := 18
pos := sort.SearchInts(intSlice,x)
fmt.Printf("Found %d at index %d in %v\n", x, pos, intSlice)
// slice need to be sort in ascending order before to use SearchInts
sort.Ints(intSlice) // slice sorted
pos = sort.SearchInts(intSlice,x)
fmt.Printf("Found %d at index %d in %v\n", x, pos, intSlice)
x = 54
pos = sort.SearchInts(intSlice,x)
fmt.Printf("Found %d at index %d in %v\n", x, pos, intSlice)
x = 99
pos = sort.SearchInts(intSlice,x)
fmt.Printf("Found %d at index %d in %v\n", x, pos, intSlice)
x = -5
pos = sort.SearchInts(intSlice,x)
fmt.Printf("Found %d at index %d in %v\n", x, pos, intSlice)
}
输出:
Found 18 at index 0 in [55 22 18 9 12 82 28 36 45 65]
Found 18 at index 2 in [9 12 18 22 28 36 45 55 65 82]
Found 54 at index 7 in [9 12 18 22 28 36 45 55 65 82]
Found 99 at index 10 in [9 12 18 22 28 36 45 55 65 82]
Found -5 at index 0 in [9 12 18 22 28 36 45 55 65 82]
SearchStrings函数在排序的字符串切片中搜索x的位置,并返回Search指定的索引。如果切片仅按排序顺序排列,则此函数有效。如果在strSlice中找到x,则返回strSlice的索引位置,否则返回索引位置,其中x适合排序切片。以下示例显示了SearchStrings() 函数的用法:
func SearchStrings(strSlice []string, x string) int
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
// string slice in unsorted order
strSlice := []string{"Texas","Washington","Montana","Alaska","Indiana","Ohio","Nevada"}
x := "Montana"
pos := sort.SearchStrings(strSlice,x)
fmt.Printf("Found %s at index %d in %v\n", x, pos, strSlice)
// slice need to be sort in ascending order before to use SearchStrings
sort.Strings(strSlice) // slice sorted
pos = sort.SearchStrings(strSlice,x)
fmt.Printf("Found %s at index %d in %v\n", x, pos, strSlice)
x = "Missouri"
pos = sort.SearchStrings(strSlice,x)
fmt.Printf("Found %s at index %d in %v\n", x, pos, strSlice)
x = "Utah"
pos = sort.SearchStrings(strSlice,x)
fmt.Printf("Found %s at index %d in %v\n", x, pos, strSlice)
x = "Ohio"
pos = sort.SearchStrings(strSlice,x)
fmt.Printf("Found %s at index %d in %v\n", x, pos, strSlice)
x = "OHIO"
pos = sort.SearchStrings(strSlice,x)
fmt.Printf("Found %s at index %d in %v\n", x, pos, strSlice)
x = "ohio"
pos = sort.SearchStrings(strSlice,x)
fmt.Printf("Found %s at index %d in %v\n", x, pos, strSlice)
}
输出:
Found Montana at index 5 in [Texas Washington Montana Alaska Indiana Ohio Nevada]
Found Montana at index 2 in [Alaska Indiana Montana Nevada Ohio Texas Washington]
Found Missouri at index 2 in [Alaska Indiana Montana Nevada Ohio Texas Washington]
Found Utah at index 6 in [Alaska Indiana Montana Nevada Ohio Texas Washington]
Found Ohio at index 4 in [Alaska Indiana Montana Nevada Ohio Texas Washington]
Found OHIO at index 4 in [Alaska Indiana Montana Nevada Ohio Texas Washington]
Found ohio at index 7 in [Alaska Indiana Montana Nevada Ohio Texas Washington]
SearchFloat64s函数在float64的排序切片中搜索x的位置,并返回Search指定的索引。如果切片仅按排序顺序排列,则此函数有效。如果在fltSlice中找到x,则返回fltSlice的索引位置,否则返回x适合排序切片的索引位置。以下示例显示了SearchFloat64s() 函数的用法:
func SearchFloat64s(fltSlice []float64, x float64)
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
// string slice in unsorted order
fltSlice := []float64{962.25, 514.251, 141.214, 96.142, 85.14}
x := 141.214
pos := sort.SearchFloat64s(fltSlice,x)
fmt.Printf("Found %f at index %d in %v\n", x, pos, fltSlice)
// slice need to be sort in ascending order before to use SearchFloat64s
sort.Float64s(fltSlice) // slice sorted
pos = sort.SearchFloat64s(fltSlice,x)
fmt.Printf("Found %f at index %d in %v\n", x, pos, fltSlice)
x = 8989.251
pos = sort.SearchFloat64s(fltSlice,x)
fmt.Printf("Found %f at index %d in %v\n", x, pos, fltSlice)
x = 10.251
pos = sort.SearchFloat64s(fltSlice,x)
fmt.Printf("Found %f at index %d in %v\n", x, pos, fltSlice)
x = 411.251
pos = sort.SearchFloat64s(fltSlice,x)
fmt.Printf("Found %f at index %d in %v\n", x, pos, fltSlice)
x = -411.251
pos = sort.SearchFloat64s(fltSlice,x)
fmt.Printf("Found %f at index %d in %v\n", x, pos, fltSlice)
}
输出:
Found 141.214000 at index 0 in [962.25 514.251 141.214 96.142 85.14]
Found 141.214000 at index 2 in [85.14 96.142 141.214 514.251 962.25]
Found 8989.251000 at index 5 in [85.14 96.142 141.214 514.251 962.25]
Found 10.251000 at index 0 in [85.14 96.142 141.214 514.251 962.25]
Found 411.251000 at index 3 in [85.14 96.142 141.214 514.251 962.25]
Found -411.251000 at index 0 in [85.14 96.142 141.214 514.251 962.25]
Search函数在string/float/int的排序切片中搜索x的位置,并返回Search指定的索引。如果在数据中找到x,则返回数据的索引位置,否则返回索引位置,其中x适合排序切片。此功能适用于升序和降序切片,而以上3个搜索功能仅适用于升序。以下示例显示了Search() 函数的用法:
sort.Search(len(data), func(i int) bool { return data[i] >= x })
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
fmt.Println("\n######## SearchInts not works in descending order ######## ")
intSlice := []int{55, 54, 53, 52, 51, 50, 48, 36, 15, 5} // sorted slice in descending
x := 36
pos := sort.SearchInts(intSlice,x)
fmt.Printf("Found %d at index %d in %v\n", x, pos, intSlice)
fmt.Println("\n######## Search works in descending order ########")
i := sort.Search(len(intSlice), func(i int) bool { return intSlice[i] <= x })
fmt.Printf("Found %d at index %d in %v\n", x, i, intSlice)
fmt.Println("\n\n######## SearchStrings not works in descending order ######## ")
// sorted slice in descending
strSlice := []string{"Washington","Texas","Ohio","Nevada","Montana","Indiana","Alaska"}
y := "Montana"
posstr := sort.SearchStrings(strSlice,y)
fmt.Printf("Found %s at index %d in %v\n", y, posstr, strSlice)
fmt.Println("\n######## Search works in descending order ########")
j := sort.Search(len(strSlice), func(j int) bool {return strSlice[j] <= y})
fmt.Printf("Found %s at index %d in %v\n", y, j, strSlice)
fmt.Println("\n######## Search works in ascending order ########")
fltSlice := []float64{10.10, 20.10, 30.15, 40.15, 58.95} // string slice in float64
z := 40.15
k := sort.Search(len(fltSlice), func(k int) bool {return fltSlice[k] >= z})
fmt.Printf("Found %f at index %d in %v\n", z, k, fltSlice)
}
输出:
######## SearchInts not works in descending order ########
Found 36 at index 0 in [55 54 53 52 51 50 48 36 15 5]
######## Search works in descending order ########
Found 36 at index 7 in [55 54 53 52 51 50 48 36 15 5]
######## SearchStrings not works in descending order ########
Found Montana at index 0 in [Washington Texas Ohio Nevada Montana Indiana Alaska]
######## Search works in descending order ########
Found Montana at index 4 in [Washington Texas Ohio Nevada Montana Indiana Alaska]
######## Search works in ascending order ########
Found 40.150000 at index 3 in [10.1 20.1 30.15 40.15 58.95]
Sort函数按升序和降序对数据接口进行排序。它首先调用数据。Len用于确定n,O(n*log(n)) 调用数据。更少和数据。交换。以下示例显示了Sort() 函数的用法:
func Sort(data Interface)
示例代码:
package main
import (
"fmt"
"sort"
)
type Mobile struct {
Brand string
Price int
}
// ByPrice implements sort.Interface for []Mobile based on
// the Price field.
type ByPrice []Mobile
func (a ByPrice) Len() int { return len(a) }
func (a ByPrice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByPrice) Less(i, j int) bool { return a[i].Price < a[j].Price }
// ByBrand implements sort.Interface for []Mobile based on
// the Brand field.
type ByBrand []Mobile
func (a ByBrand) Len() int { return len(a) }
func (a ByBrand) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByBrand) Less(i, j int) bool { return a[i].Brand > a[j].Brand }
func main() {
mobile := []Mobile{
{"Sony", 952},
{"Nokia", 468},
{"Apple", 1219},
{"Samsung", 1045},
}
fmt.Println("\n######## Before Sort #############\n")
for _, v := range mobile {
fmt.Println(v.Brand, v.Price)
}
fmt.Println("\n\n######## Sort By Price [ascending] ###########\n")
sort.Sort(ByPrice(mobile))
for _, v := range mobile {
fmt.Println(v.Brand, v.Price)
}
fmt.Println("\n\n######## Sort By Brand [descending] ###########\n")
sort.Sort(ByBrand(mobile))
for _, v := range mobile {
fmt.Println(v.Brand, v.Price)
}
}
输出:
######## Before Sort #############
Sony 952
Nokia 468
Apple 1219
Samsung 1045
######## Sort By Price [ascending] ###########
Nokia 468
Sony 952
Samsung 1045
Apple 1219
######## Sort By Brand [descending] ###########
Sony 952
Samsung 1045
Nokia 468
Apple 1219
IsSorted函数报告数据排序依据是返回true还是false。以下示例显示了IsSorted() 函数的用法:
func IsSorted(data Interface) bool
示例代码:
package main
import (
"fmt"
"sort"
)
type Mobile struct {
Brand string
Price int
}
// ByPrice implements sort.Interface for []Mobile based on
// the Price field.
type ByPrice []Mobile
func (a ByPrice) Len() int { return len(a) }
func (a ByPrice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByPrice) Less(i, j int) bool { return a[i].Price < a[j].Price }
func main() {
mobile1 := []Mobile{
{"Sony", 952},
{"Nokia", 468},
{"Apple", 1219},
{"Samsung", 1045},
}
fmt.Println("\nFound mobile1 price is sorted :", sort.IsSorted(ByPrice(mobile1))) // false
mobile2 := []Mobile{
{"Sony", 452},
{"Nokia", 768},
{"Apple", 919},
{"Samsung", 1045},
}
fmt.Println("\nFound mobile2 price is sorted :", sort.IsSorted(ByPrice(mobile2))) // true
}
输出:
Found mobile1 price is sorted : false
Found mobile2 price is sorted : true
Slice函数根据提供的less函数对提供的切片进行排序。如果提供的接口不是切片,则该函数会崩溃。以下示例显示了Slice() 函数的用法:
func Slice(slice interface{}, less func(i, j int) bool)
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
mobile := []struct {
Brand string
Price int
}{
{"Nokia", 700},
{"Samsung", 505},
{"Apple", 924},
{"Sony", 655},
}
sort.Slice(mobile, func(i, j int) bool { return mobile[i].Brand < mobile[j].Brand })
fmt.Println("\n\n######## Sort By Brand [ascending] ###########\n")
for _, v := range mobile {
fmt.Println(v.Brand, v.Price)
}
sort.Slice(mobile, func(i, j int) bool { return mobile[i].Brand > mobile[j].Brand })
fmt.Println("\n\n######## Sort By Brand [descending] ###########\n")
for _, v := range mobile {
fmt.Println(v.Brand, v.Price)
}
sort.Slice(mobile, func(i, j int) bool { return mobile[i].Price < mobile[j].Price })
fmt.Println("\n\n######## Sort By Price [ascending] ###########\n")
for _, v := range mobile {
fmt.Println(v.Brand, v.Price)
}
mobile = []struct {
Brand string
Price int
}{
{"MI", 900},
{"OPPO", 305},
{"iPhone", 924},
{"sony", 655},
}
sort.Slice(mobile, func(i, j int) bool { return mobile[i].Brand < mobile[j].Brand })
fmt.Println("\n\n######## Sort By Brand [ascending] ###########\n")
for _, v := range mobile {
fmt.Println(v.Brand, v.Price)
}
}
输出:
######## Sort By Brand [ascending] ###########
Apple 924
Nokia 700
Samsung 505
Sony 655
######## Sort By Brand [descending] ###########
Sony 655
Samsung 505
Nokia 700
Apple 924
######## Sort By Price [ascending] ###########
Samsung 505
Sony 655
Nokia 700
Apple 924
######## Sort By Brand [ascending] ###########
MI 900
OPPO 305
iPhone 924
sony 655
此SliceIsSorted函数测试切片是否已排序。如果数据已排序,则返回true或false。以下示例显示了SliceIsSorted() 函数的用法:
func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
mobile := []struct {
Brand string
Price int
}{
{"Nokia", 700},
{"Samsung", 505},
{"Apple", 924},
{"Sony", 655},
}
result := sort.SliceIsSorted(mobile, func(i, j int) bool { return mobile[i].Price < mobile[j].Price })
fmt.Println("Found price sorted:", result) // false
mobile = []struct {
Brand string
Price int
}{
{"Nokia", 700},
{"Samsung", 805},
{"Apple", 924},
{"Sony", 955},
}
result = sort.SliceIsSorted(mobile, func(i, j int) bool { return mobile[i].Price < mobile[j].Price })
fmt.Println("Found price sorted:", result) // true
mobile = []struct {
Brand string
Price int
}{
{"iPhone", 900},
{"MI", 805},
{"OPPO", 724},
{"Sony", 655},
}
result = sort.SliceIsSorted(mobile, func(i, j int) bool { return mobile[i].Brand < mobile[j].Brand })
fmt.Println("Found brand sorted:", result) // false
}
输出:
Found price sorted: false
Found price sorted: true
Found brand sorted: false
IntSlice将Interface的方法附加到 []int,并按递增顺序排序。Len曾经找到切片的长度。Search返回将SearchInts应用于接收器和x的结果。排序 用于对切片进行排序。 以下示例显示了IntSlice() 函数的用法:
type IntSlice []int
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
s := []int{9, 22, 54, 33, -10, 40} // unsorted
sort.Sort(sort.IntSlice(s))
fmt.Println(s) // sorted
fmt.Println("Length of Slice: ", sort.IntSlice.Len(s)) // 6
fmt.Println("40 found in Slice at position: ", sort.IntSlice(s).Search(40)) // 4
fmt.Println("82 found in Slice at position: ", sort.IntSlice(s).Search(82)) // 6
fmt.Println("6 found in Slice at position: ", sort.IntSlice(s).Search(6)) // 0
}
输出:
[-10 9 22 33 40 54]
Length of Slice: 6
40 found in Slice at position: 4
82 found in Slice at position: 6
6 found in Slice at position: 1
StringSlice将Interface的方法附加到 []string,并按递增顺序排序。Len曾经找到切片的长度。Search返回将SearchStrings应用于接收方和x的结果。排序 用于对切片进行排序。以下示例显示了StringSlice函数的用法:
type StringSlice []string
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
s := []string{"Washington","Texas","Ohio","Nevada","Montana","Indiana","Alaska"} // unsorted
sort.Sort(sort.StringSlice(s))
fmt.Println(s) // sorted
fmt.Println("Length of Slice: ", sort.StringSlice.Len(s)) // 7
fmt.Println("Texas found in Slice at position: ", sort.StringSlice(s).Search("Texas")) // 5
fmt.Println("Montana found in Slice at position: ", sort.StringSlice(s).Search("Montana")) // 2
fmt.Println("Utah found in Slice at position: ", sort.StringSlice(s).Search("Utah")) // 6
fmt.Println("OHIO found in Slice at position: ", sort.StringSlice(s).Search("OHIO")) // 4
fmt.Println("Ohio found in Slice at position: ", sort.StringSlice(s).Search("Ohio")) // 4
fmt.Println("ohio found in Slice at position: ", sort.StringSlice(s).Search("ohio")) // 7
}
输出:
[Alaska Indiana Montana Nevada Ohio Texas Washington]
Length of Slice: 7
Texas found in Slice at position: 5
Montana found in Slice at position: 2
Utah found in Slice at position: 6
OHIO found in Slice at position: 4
Ohio found in Slice at position: 4
ohio found in Slice at position: 7
Float64Slice将Interface的方法附加到 []float64,并按递增顺序排序。Len曾经找到切片的长度。Search返回将SearchFloat64s应用于接收器和x的结果。排序 用于对切片进行排序。以下示例显示了Float64Slice函数的用法:
type Float64Slice []float64
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
s := []float64{85.201, 14.74, 965.25, 125.32, 63.14} // unsorted
sort.Sort(sort.Float64Slice(s))
fmt.Println(s) // sorted
fmt.Println("Length of Slice: ", sort.Float64Slice.Len(s)) // 5
fmt.Println("123.32 found in Slice at position: ", sort.Float64Slice(s).Search(125.32)) // 3
fmt.Println("999.15 found in Slice at position: ", sort.Float64Slice(s).Search(999.15)) // 5
fmt.Println("12.14 found in Slice at position: ", sort.Float64Slice(s).Search(12.14)) // 0
}
输出:
[14.74 63.14 85.201 125.32 965.25]
Length of Slice: 5
123.32 found in Slice at position: 3
999.15 found in Slice at position: 5
12.14 found in Slice at position: 0
Reverse函数以相反的顺序返回切片。以下示例显示了Reverse() 函数的用法:
func Reverse(data Interface) Interface
示例代码:
package main
import (
"fmt"
"sort"
)
func main() {
a := []int{15, 4, 33, 52, 551, 90, 8, 16, 15, 105} // unsorted
sort.Sort(sort.Reverse(sort.IntSlice(a)))
fmt.Println("\n",a)
a = []int{-15, -4, -33, -52, -551, -90, -8, -16, -15, -105} // unsorted
sort.Sort(sort.Reverse(sort.IntSlice(a)))
fmt.Println("\n",a)
b := []string{"Montana","Alaska","Indiana","Nevada","Washington","Ohio","Texas"} // unsorted
sort.Sort(sort.Reverse(sort.StringSlice(b)))
fmt.Println("\n",b)
b = []string{"ALASKA","indiana","OHIO","Nevada","Washington","TEXAS","Montana"} // unsorted
sort.Sort(sort.Reverse(sort.StringSlice(b)))
fmt.Println("\n",b)
c := []float64{90.10, 80.10, 160.15, 40.15, 8.95} // unsorted
sort.Sort(sort.Reverse(sort.Float64Slice(c)))
fmt.Println("\n",c)
c = []float64{-90.10, -80.10, -160.15, -40.15, -8.95} // unsorted
sort.Sort(sort.Reverse(sort.Float64Slice(c)))
fmt.Println("\n",c)
}
输出:
[551 105 90 52 33 16 15 15 8 4]
[-4 -8 -15 -15 -16 -33 -52 -90 -105 -551]
[Washington Texas Ohio Nevada Montana Indiana Alaska]
[indiana Washington TEXAS OHIO Nevada Montana ALASKA]
[160.15 90.1 80.1 40.15 8.95]
[-8.95 -40.15 -80.1 -90.1 -160.15]
上下文包最佳实践
在Go中使用上下文包有几个最佳实践:
- 使用context.WithCancel,context.WithTimeout或context.WithDeadline创建带有超时或取消信号的上下文。
- 始终将上下文作为第一个参数传递给可能需要很长时间才能完成的函数,例如网络请求或数据库查询。
- 使用context.Value存储和检索与上下文关联的值,例如用户ID或请求ID。
- 使用context.WithValue基于现有上下文创建新上下文,并将其他值与其关联。
- 检查上下文的Done通道,查看它是否已被取消。
- 在整个应用程序中使用上下文包来传播请求范围的值和取消信号,而不是使用全局变量或手动信号。
- 避免使用context.Background(),因为它没有超时或取消信号,而是使用context.TODO() 表示上下文稍后将被调用方替换。
- 不要将上下文存储在结构中,而是将它们作为参数传递给函数。
- 始终检查上下文感知函数的错误返回值,以查看上下文是否被取消或超时。
Go中的上下文包用于跨API边界传递请求范围的值、取消信号和截止时间。它可用于存储元数据、取消信号、超时和其他请求范围的值。上下文包提供了一种取消长时间运行的操作以及跨API边界存储元数据的方法。它通常与http包一起使用,以管理HTTP请求的请求范围值和取消信号。
它允许您在多个函数调用和goroutine之间传播请求范围的值,从而更轻松地管理应用程序中的信息流。
context.Context是使用context.With*函数创建,例如context.WithValue,context.WithCancel 或 context.WithTimeout。这些函数返回新的上下文,携带指定值或信号的上下文值。
context.Context可以作为参数传递给需要访问请求范围值或侦听取消信号的函数和方法。然后,这些函数可以使用context.Value和context.Done访问上下文中存储的值和信号的done方法。
在需要取消长时间运行的操作或跨多个goroutine传播请求范围的值的情况下,上下文包特别有用。它通常用于服务器端编程和其他并发方案。
应始终将上下文作为第一个参数传递给执行可能被取消的工作的任何函数。
例如,HTTP服务器可以使用上下文在客户端断开连接时取消请求的工作,数据库包可以使用上下文来实现可取消的查询,等等。
context包定义了 Context 类型,该类型是一个Go接口,具有四个方法,分别名为Deadline()、Done()、Err() 和Value():
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done()
Err()
Value(key)
}
上下文接口定义的方法
方法 | 描述 |
---|---|
Value(key) | 返回对应的值 |
Done() | 此方法返回可用于接收取消通知的频道 |
Deadline() | 此方法返回time.Time, 表示请求的截止日期,如果没有指定截止日期,则布尔值为false。 |
Err() | 此方法返回一个错误,指示完成通道接收信号的原因。上下文包定义了两个可用于比较错误的变量:Canceled表示请求已取消,DeadlineExeeded表示截止日期已过。 |
用于创建上下文值的上下文包函数
方法 | 描述 |
---|---|
Background() | 此方法返回默认上下文,从中派生其他上下文。 |
WithCancel(ctx) | 此方法返回一个上下文和一个取消函数。 |
WithDeadline(ctx, time) | 此方法返回一个带有截止日期的上下文,该截止日期用time.Time表示值。 |
WithTimeout(ctx, duration) | 此方法返回一个带有截止日期的上下文,该截止日期用time.Time表示值。 |
WithValue(ctx, key, val) | 此方法返回一个包含指定键值对的上下文。 |
context.WithCancel
下面是一个示例,说明context.WithCancel可以在Go中使用:
package main
import (
"context"
"fmt"
"time"
)
func doWork(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Work done!")
return
default:
fmt.Println("Working...")
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // 推迟执行cancel
go doWork(ctx)
// Wait for a while before canceling the context
select {
case <-ctx.Done():
case <-time.After(time.Second * 3):
cancel()
}
}
在此示例中,我们使用context创建一个新的上下文 ctx.WithCancel(context.background())中。context.Background() 函数返回一个空的context。context.WithCancel 返回一个新的上下文和一个取消函数。我们推迟取消函数,以便在主函数退出时调用它。在 doWork 函数中,它将检查上下文是否已完成,如果是,则返回该函数。
在main函数中,我们正在运行一个goroutine,并通过传递上下文来完成其中的工作。等待3秒后,main函数会通过调用cancel函数来取消上下文,这将使上下文的Done通道关闭。因此,doWork函数将从Done通道接收,打印 "Work done!" 并返回。
context.WithTimeout
在Go中,您可以使用context.WithTimeout函数创建一个新上下文,该上下文在指定的超时时间过后被取消。该函数采用两个参数:现有上下文和超时持续时间。
下面是如何使用上下文的示例。WithTimeout创建在5秒后取消的上下文:
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
// Do some work
select {
case <-ctx.Done():
fmt.Println("Work completed")
case <-time.After(10 * time.Second):
fmt.Println("Work took longer than 10 seconds")
}
}
在此示例中,上下文是通过调用context.WithTimeout与后台上下文5秒的超时创建。该函数返回一个新上下文和一个用于取消上下文的函数。cancel函数在defer语句中调用,以确保在函数返回时取消上下文。select语句用于等待上下文完成或超时结束。
您还可以使用ctx检查上下文是否已完成。Done() 通道,您可以在select语句或循环中使用此通道来检查上下文是否完成,如果完成则意味着上下文已过期。
context.WithDeadline
在Go中,context.WithDeadline 函数创建具有关联截止时间的新上下文。截止日期是一个特定的时间点,在此时间点之后,上下文将被视为"死亡",任何相关工作都将被取消。该函数接受两个参数:现有上下文和截止时间。它返回一个新的上下文,该上下文将在指定的截止时间取消。
下面是一个示例:
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx := context.Background()
deadline := time.Now().Add(time.Second * 5)
ctx, cancel := context.WithDeadline(ctx, deadline)
defer cancel()
select {
case <-time.After(time.Second * 10):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
}
在此示例中,将创建一个背景上下文,然后设置未来5秒的截止时间。WithDeadline 函数用于基于背景上下文创建具有指定截止时间的新上下文。select语句用于等待上下文被取消或等待10秒过去。如果在10秒之前取消上下文,它将打印错误消息上下文截止时间超过,否则将打印"overslept"
使用Context的SQL查询超时
要在Golang中使用超时的SQL查询,您可以使用上下文包来设置查询执行的截止时间。首先,使用上下文创建具有超时的context.WithTimeout函数。然后,将上下文作为第一个参数传递给查询执行函数(例如db.QueryContext() 或db.ExecContext())。
下面是如何为SELECT查询设置1秒超时的示例:
package main
import (
"context"
"database/sql"
"fmt"
"time"
)
func main() {
// Open a connection to the database
db, _ := sql.Open("driverName", "dataSourceName")
// Create a context with a timeout of 1 second
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
// Execute the query with the context
rows, err := db.QueryContext(ctx, "SELECT * FROM table")
if err != nil {
fmt.Println(err)
}
defer rows.Close()
// Handle the query results
// ...
}
使用上下文超时读取文件
在Go中,可以使用上下文包来设置读取文件的超时时间。下面是一个示例:
package main
import (
"context"
"fmt"
"io/ioutil"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
data, err := ioutil.ReadFile("example.txt", ctx)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(string(data))
}
在此示例中,我们首先使用context创建一个超时为2秒的context.WithTimeout。然后,我们将此上下文传递给ioutil。ReadFile读取文件"example.txt"的内容。如果读取文件的时间超过2秒,则上下文的Done通道将关闭,并且ioutil.ReadFile返回错误。
将上下文用于HTTP
在Go中,您可以使用上下文包来设置HTTP请求的超时。下面是一个示例:
package main
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
req, err := http.NewRequest("GET", "https://example.com", nil)
if err != nil {
fmt.Println("Error:", err)
return
}
req = req.WithContext(ctx)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(string(body))
}
在此示例中,我们首先使用context创建一个超时为2秒的context.WithTimeout。然后,我们使用req.WithContext(ctx) 将此上下文附加到HTTP请求中。当我们使用http.Client.Do方法发出请求时,如果在收到响应之前关闭了上下文的Done通道,它将自动取消请求。
您还可以使用客户端库(如golang.org/x/net/context/ctxhttp)发出带有上下文的http请求,该库具有Get和Post方法,该方法将上下文作为第一个参数并返回响应和错误。
package main
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"time"
"golang.org/x/net/context/ctxhttp"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
resp, err := ctxhttp.Get(ctx, nil, "https://example.com")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(string(body))
}
此示例使用ctxhttp.Get方法向"https://example.com"发出GET请求,超时为2秒。
请务必注意,在这两种情况下,如果上下文关闭了Done通道,则请求将被取消,但不会关闭连接。应用程序负责关闭连接。
使用Context作为键值存储
在Go中,您可以使用上下文包来存储可以与请求或一段代码一起传递的键值数据对。这允许您将其他信息与请求或代码段相关联,而不必将其作为显式参数传递。下面是一个示例:
package main
import (
"context"
"fmt"
)
func main() {
ctx := context.WithValue(context.Background(), "user_id", "12345")
// use the context in a function
processRequest(ctx)
}
func processRequest(ctx context.Context) {
userID := ctx.Value("user_id").(string)
fmt.Println("User ID:", userID)
}
在此示例中,我们首先使用context创建一个上下文。WithValue方法。我们传递上下文。Background() 作为父上下文,以及方法的键值对 "user_id" 和 "12345"。然后,我们将此上下文传递给processRequest函数。在函数中,我们使用Value方法从上下文中检索"user_id"值,并将其打印出来。
请务必注意,上下文值仅用于传输进程和API边界的请求范围数据,而不用于将可选参数传递给函数。如果需要将可选参数传递给函数,最好使用结构或函数选项模式。
此外,上下文值不是线程安全的,如果您处于并发环境中,请使用sync.Map或同等产品。