首页 > 其他分享 >go的day4

go的day4

时间:2023-03-11 09:22:50浏览次数:36  
标签:Distance 调用 Point day4 func go 方法 fmt

面向对象特征

方法

假设有两个方法,一个方法的接收者是指针类型,一个方法的接收者是值类型,那么:

+对于值类型的变量和指针类型的变量,这两个方法有什么区别?
+如果这两个方法是为了实现一个接口,那么这两个方法都可以调用吗?
+如果方法是嵌入到其他结构体中的,那么上面两种情况又是怎样的?

package main


import "fmt"


//定义一个结构体
type T struct {
    name string
}


func (t T) method1() {
    t.name = "new name1"
}


func (t *T) method2() {
    t.name = "new name2"
}


func main() {


    t := T{"old name"}


    fmt.Println("method1 调用前 ", t.name)
    t.method1()
    fmt.Println("method1 调用后 ", t.name)


    fmt.Println("method2 调用前 ", t.name)
    t.method2()
    fmt.Println("method2 调用后 ", t.name)
}

运行结果:

method1 调用前  old name
method1 调用后  old name
method2 调用前  old name
method2 调用后  new name2

当调用t.method1()时相当于method1(t),实参和行参都是类型 T,可以接受。此时在method1()中的t只是参数t的值拷贝,所以method1()的修改影响不到main中的t变量。

当调用t.method2()=>method2(t),这是将 T 类型传给了 *T 类型,go可能会取 t 的地址传进去:method2(&t)。所以 method2() 的修改可以影响 t。

T 类型的变量这两个方法都是拥有的。

方法值和方法表达式

方法值

我们经常选择一个方法,并且在同一个表达式里执行,比如常见的p.Distance()形式,实际上将其分成两步来执行也是可能的。p.Distance叫作“选择器”,选择器会返回一个方法"值"一个将方法(Point.Distance)绑定到特定接收器变量的函数。这个函数可以不通过指定其接收器即可被调用;即调用时不需要指定接收器,只要传入函数的参数即可:

package main


import "fmt"
import "math"


type Point struct{ X, Y float64 }


//这是给struct Point类型定义一个方法
func (p Point) Distance(q Point) float64 {
    return math.Hypot(q.X-p.X, q.Y-p.Y)
}


func main() {


    p := Point{1, 2}
    q := Point{4, 6}


    distanceFormP := p.Distance   // 方法值(相当于C语言的函数地址,函数指针)
    fmt.Println(distanceFormP(q)) // "5"
    fmt.Println(p.Distance(q))    // "5"


    //实际上distanceFormP 就绑定了 p接收器的方法Distance


    distanceFormQ := q.Distance   //
    fmt.Println(distanceFormQ(p)) // "5"
    fmt.Println(q.Distance(p))    // "5"


    //实际上distanceFormQ 就绑定了 q接收器的方法Distance
}

在一个包的API需要一个函数值、且调用方希望操作的是某一个绑定了对象的方法的话,方法"值"会非常实用.
举例来说,下面例子中的time.AfterFunc这个函数的功能是在指定的延迟时间之后来执行一个(译注:另外的)函数。且这个函数操作的是一个Rocket对象r

type Rocket struct { /* ... */ }
func (r *Rocket) Launch() { /* ... */ }
r := new(Rocket)
time.AfterFunc(10 * time.Second, func() { r.Launch() })

直接用方法"值"传入AfterFunc的话可以更为简短:

time.AfterFunc(10 * time.Second, r.Launch)

省掉了上面那个例子里的匿名函数。

方法表达式

和方法"值"相关的还有方法表达式。当调用一个方法时,与调用一个普通的函数相比,我们必须要用选择器(p.Distance)语法来指定方法的接收器。
当T是一个类型时,方法表达式可能会写作T.f或者(*T).f,会返回一个函数"值",这种函数会将其第一个参数用作接收器,所以可以用通常(译注:不写选择器)的方式来对其进行调用:

package main


import "fmt"
import "math"


type Point struct{ X, Y float64 }


//这是给struct Point类型定义一个方法
func (p Point) Distance(q Point) float64 {
    return math.Hypot(q.X-p.X, q.Y-p.Y)
}


func main() {


    p := Point{1, 2}
    q := Point{4, 6}




    distance1 := Point.Distance //方法表达式, 是一个函数值(相当于C语言的函数指针)
    fmt.Println(distance1(p, q))
    fmt.Printf("%T\n", distance1) //%T表示打出数据类型 ,这个必须放在Printf使用


    distance2 := (*Point).Distance //方法表达式,必须传递指针类型
    distance2(&p, q)
    fmt.Printf("%T\n", distance2)


}

执行结果

5
func(main.Point, main.Point) float64
func(*main.Point, main.Point) float64
// 这个Distance实际上是指定了Point对象为接收器的一个方法func (p Point) Distance(),
// 但通过Point.Distance得到的函数需要比实际的Distance方法多一个参数,
// 即其需要用第一个额外参数指定接收器,后面排列Distance方法的参数。
// 看起来本书中函数和方法的区别是指有没有接收器,而不像其他语言那样是指有没有返回值。

当你根据一个变量来决定调用同一个类型的哪个函数时,方法表达式就显得很有用了。你可以根据选择来调用接收器各不相同的方法。下面的例子,变量op代表Point类型的addition或者subtraction方法,Path.TranslateBy方法会为其Path数组中的每一个Point来调用对应的方法:

package main


import "fmt"
import "math"


type Point struct{ X, Y float64 }


//这是给struct Point类型定义一个方法
func (p Point) Distance(q Point) float64 {
        return math.Hypot(q.X-p.X, q.Y-p.Y)
}


func (p Point) Add(another Point) Point {
        return Point{p.X + another.X, p.Y + another.Y}
}


func (p Point) Sub(another Point) Point {
        return Point{p.X - another.X, p.Y - another.Y}
}


func (p Point) Print() {
        fmt.Printf("{%f, %f}\n", p.X, p.Y)
}


//定义一个Point切片类型 Path
type Path []Point


//方法的接收器 是Path类型数据, 方法的选择器是TranslateBy(Point, bool)
func (path Path) TranslateBy(another Point, add bool) {
        var op func(p, q Point) Point //定义一个 op变量 类型是方法表达式 能够接收Add,和 Sub方法
        if add == true {
                op = Point.Add //给op变量赋值为Add方法
        } else {
                op = Point.Sub //给op变量赋值为Sub方法
        }


        for i := range path {
                //调用 path[i].Add(another) 或者 path[i].Sub(another)
                path[i] = op(path[i], another)
                path[i].Print()
        }
}


func main() {

        points := Path{
                {10, 10},
                {11, 11},
        }


        anotherPoint := Point{5, 5}


        points.TranslateBy(anotherPoint, false)


        fmt.Println("------------------")


        points.TranslateBy(anotherPoint, true)
}

运行结果:

{5.000000, 5.000000}
{6.000000, 6.000000}
------------------
{10.000000, 10.000000}
{11.000000, 11.000000}

标签:Distance,调用,Point,day4,func,go,方法,fmt
From: https://www.cnblogs.com/coverupforV/p/17205268.html

相关文章

  • Golang使用命令行改变PATH路径
    goenv-wENV_VAR=value这是内置在goCLI中的跨平台解决方案,将来应该可以为您节省一些时间。例:goenv-wGOPATH=/your/desired/path输入goenv以检查当前环境......
  • 【转载】一招完美解决vscode安装go插件失败问题
    前置从https://studygolang.com/dl下载go1.14.6.windows-amd64.msi安装即可,安装路径选择默认,安装完成后会自动帮你配置环境变量不用自己配置了打开cmd,查看是否安装完成......
  • Cryptanalyzing and Improving a Novel Color Image Encryption Algorithm Using RT-E
    CryptanalyzingandImprovingaNovelColorImageEncryptionAlgorithmUsingRT-EnhancedChaoticTentMaps基于RT增强混沌帐篷映射的彩色图像加密算法文章信息博客......
  • 【希尔排序ShellSort算法详解】Java/Go/Python/JS/C不同语言实现
    【希尔排序算法详解】Java/Go/Python/JS/C不同语言实现 说明希尔排序(ShellSort)是插入排序的一种改进版,也称递减增量排序算法(DiminishingIncrementSort),其实质是将数......
  • Golang项目使用Dockerfile部署
    前言关于在构建golang编写的web项目中使用dockerfile的一些总结。通过查阅资料后,写下了如下配置:一般模式会安装golang编译环境,镜像文件包会比较大。#构建golang运行......
  • (转)Go语言ioutil包详解
    原文:https://juejin.cn/post/7070917217776304141前言Go语言ioutil包中提供了一些常用、方便的IO操作函数,我们在平时的时候中可以直接拿来使用。对于IO读操作来说,比较......
  • (转)golang 读写文件的四种方式
    原文:https://blog.csdn.net/whatday/article/details/103938124读文件读取的文件放在file/test:也就是file包下的test这个文件,里面写多一点文件读文件方式一:利用ioutil.R......
  • golang 自行实现一个base64加密
    packagemainimport( "fmt" "strconv")constbase64table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"funcMybase64(astring){......
  • go 协程收集 不同函数结果和error
    需要用到"golang.org/x/sync/errgroup"这个库改成并行的方式这个总共执行4s就可以......
  • 七牛云+picGo:搭建图床
    【场景】:图床就是图片的云存储。比如在用markdown记笔记时,需要插入图片,但是这个图片是本地的,如果你把md给别人或者传到网上,就无法显示图片了。【解决】:1。注册......