您现在的位置是:首页 >技术杂谈 >golang学习第三天网站首页技术杂谈
golang学习第三天
今天学习的主要内容有Methods(方法)、interfaces(接口)、Type assertions(类型断言)、Stringers、Readers。老规矩先展示全部代码
package main
import (
"fmt"
"io"
"math"
"strings"
"time"
)
// 声明结构体Vertex
type Vertex struct {
X, Y float64
}
// 定义Vertex类型的方法Abs
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// 自定义类型
type MyFloat float64
// 定义MyFloat类型的方法Abs
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
// 对象接收者类型Vertex
func (v Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
fmt.Println("v1: ", v)
}
// 指针接收者类型*Vertex
func (v *Vertex) ScalePointer(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
// 指针接收者类型*Vertex
func (v *Vertex) AbsPointer() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// 定义接口
type Abser interface {
Abs() float64
}
// 定义接口
type I interface {
M()
}
// 定义结构体
type T struct {
S string
}
// func (t T) M() {
// fmt.Println(t.S)
// }
//
// 给M方法添加指针接收者*T
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
// 自定义类型F
type F float64
// 给M()方法添加对象接收者F
func (f F) M() {
fmt.Println(f)
}
// 判断接口类型
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v
", v, v*2)
case string:
fmt.Printf("%q is %v bytes long
", v, len(v))
default:
fmt.Printf("I don't know about type %T
", v)
}
}
// 定义Person结构体
type Person struct {
Name string
Age int
}
// person实现接口Stringers里的String()方法
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)
", p.Name, p.Age)
}
// 定义字节数组
type IPAddr [4]byte
// IPAddr实现接口Stringers里的String()方法
func (ip IPAddr) String() string {
return fmt.Sprintf("%v.%v.%v.%v
", ip[0], ip[1], ip[2], ip[3])
}
// 自定义error结构体
type MyError struct {
when time.Time
what string
}
// MyError实现error接口中的Error方法
func (e *MyError) Error() string {
return fmt.Sprintf("at %v %s
", e.when, e.what)
}
// 定义run方法返回一个MyError错误
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
// 自定义float64类型
type ErrNegativeSqrt float64
// ErrNegativeSqrt类型实现error接口中的Error方法
func (e ErrNegativeSqrt) Error() string {
if e < 0 {
return fmt.Sprintf("cannot sqrt negative number: %f
", e)
}
return ""
}
// Sqrt方法返回自定义错误
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, ErrNegativeSqrt(f)
}
return math.Sqrt(f), ErrNegativeSqrt(f)
}
func main() {
// methods ------------------------------
v := Vertex{3, 4}
fmt.Println(v.Abs())
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
v.Scale(10)
fmt.Println(v.Abs())
p := &v
fmt.Printf("Before scalling: %+v ,Abs: %v
", p, p.Abs())
v.ScalePointer(5)
// p.Scale(5)
fmt.Printf("After scalling: %+v, Abs: %v
", p, p.Abs())
//interface---------------------------------------------
var a Abser
a = f
a = p
fmt.Println(a)
var i I
describe(i)
// i.M()
i = &T{"Hello interface"}
describe(i)
i.M()
var f1 = F(math.Pi)
i = f1
describe(i)
i.M()
var t *T
i = t
describe(i)
i.M()
var ii interface{}
describe(ii)
ii = 12
describe(ii)
ii = "Interface"
describe(ii)
// type ----------------------------------------
var ai interface{} = "Hello"
s := ai.(string)
fmt.Println(s)
af, ok := ai.(float64)
fmt.Println(af, ok)
//trigger a panic
// af = ai.(float64)
//type switches
do(21)
do("Type")
do(true)
//Stringers
felix := Person{"Felix", 28}
george := Person{"George", 30}
fmt.Println(felix, george)
hosts := map[string]IPAddr{
"Kobbe": {127, 0, 0, 1},
"James": {192, 168, 1, 1},
}
for name, ip := range hosts {
fmt.Printf("%v : %v
", name, ip)
}
//error -------------------------------------
if err := run(); err != nil {
fmt.Println(err)
}
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
//readers --------------------------------
r := strings.NewReader("Hello, Readers!")
b := make([]byte, 8)
for {
n, err := r.Read(b)
fmt.Printf("n=%v, err=%v, b=%v
", n, err, b)
fmt.Printf("b[:n]=%q
", b[:n])
if err == io.EOF {
break
}
}
}
// 打印接口值和类型
func describe(i interface{}) {
fmt.Printf("(%v, %T)
", i, i)
}
一、Methods方法
1.Go语言中没有class,但是可以给一个自定义类型添加方法,方法就是一个带有特殊接收者的函数,接收者定义要写在方法名称前,参照如下定义格式
type Vertex struct {
X, Y float64
}
//给Abs方法添加接收者,类型是Vertex,名称是v
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
2.方法和带有接收者参数的函数是等价的,如下写法和1中的效果一样
func Abs(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
3.除了struct也可以给其他自定义类型添加方法
type MyFloat float64
func (f MyFloat) Abs() float64 {
return float64(f)
}
4.指针接收者,可以给一个方法添加指针接收者,接收者的类型就是*T,好处是可以修改指针指向的数据,避免大数据类型的拷贝开销,实际编程中指针接收者使用频率更高一些。
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
//定义指针接收者时,也可以通过对象来调用,go会自动进行转换
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
v.Scale(10) //和(&v).Scale(10)等价
fmt.Println(v.Abs()) //50
}
二、Interfaces接口
1.接口是一些方法声明的组合,实现了接口所有方法的变量可以赋值给接口变量,好处是可以通过接口来写一些公用方法,多态等
type Abser interface {
Abs() float64
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
return float(f)
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X+v.Y*v.Y)
}
func main() {
f := MyFloat(16)
v := Vertex{3, 4}
var a Abser
a = f //MyFloat 实现了Abser
a = &v //*Vertex实现了Abser
a = v //error Vertex没有实现Abser
fmt.Println(a.Abs()) //5
}
2.一个类型实现一个接口是通过实现接口里的方法,这个实现也可以在其他的package里,这里的接口中方法定义和实现是隔离开的,接口值可以看成一个元祖(value,type),每个接口变量都有明确的类型,这样执行接口方法是才能找到对应的实现
type I interface {
M()
}
type F float64
func (f F) M() {
fmt.Println(f)
}
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
func main () {
var i I
i = F(math.Pi)
describe(i)
i.M()
i = &T{"Hello"}
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T) ", i, i)
}
3.在Go中,nil接收者也是可以调用接口方法的
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func main() {
var i I
i.M() //panic: 当type和value都为nil时不可以调用M
var t *T
i = t
i.M() //可以调用成功
}
4.空接口可以被赋值为任意类型值
var i interface{}
i = 24
i = "Empty"
i = true
5.Type assertions类型断言,可以取出接口的实际值
var i interface{} = "Hello"
v, ok := i.(string)
fmt.Println(v, ok)
f = i.(float64) //panic
6.Type switches可以通过switch语句来判断接口类型
func do(i interface{}) {
switch v:=i.(type) {
case int:
fmt.Printf("Twice %v is %v ", v, v*2)
case string:
fmt.Printf("%q is %v bytes long ", v, len(v))
default:
fmt.Printf("I don't know about type %T ", v)
}
}
func main () {
do(20) // Twice 20 is 40
do("hello") //hello is 5 bytes long
do(true) //I don't know about type bool
}
三、Stringers
1.Stringer定义在fmt包中,实现了String方法后,通过fmt打印时会把自身按照string类型输出
type Stringer interface {
String() string
}
type Person struct {
Name string
Age int
}
func (p Person) String() string {
fmt.Printf("%v ( %v years) ", p.Name, p.Age)
}
func main() {
a := Person{"Kobbe", 34}
b := Person{"James", 40}
fmt.Println(a,b)
}
四、Errors
1.Go中表示错误值用error状态
type Error interface {
Error() string
}
type MyError struct {
when time.Time
what string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v %v ", e.when, e.what)
}
func run() error {
return &MyError {
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
五、Readers
1.定义在io包中,用来读取stream数据,当stream结束时会返回io.EOF错误
import (
"fmt"
"io"
"strings"
)
func main () {
r := strings.NewReader("Hello, Reader!")
b := make([]byte, 8)
for {
n, err := r.Read(b)
fmt.Printf("n=%v err=%v b = %v ", n, err, b)
fmt.Printf("b[:n]=%q ", b[:n])
if err == io.EOF {
break
}
}
}
结果:
n = 8 err = <nil> b = [72 101 108 108 111 44 32 82] b[:n] = "Hello, R"
n = 6 err = <nil> b = [101 97 100 101 114 33 32 82] b[:n] = "eader!"
n = 0 err = EOF b = [101 97 100 101 114 33 32 82] b[:n] = ""
以上就是今天所学内容,明天继续。。。有问题欢迎一起讨论!





QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
U8W/U8W-Mini使用与常见问题解决
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结