技术

IT这个行当之需求与时间管理 golang结构体和包中的类型或基础类型定义方法 golang中结构体的初始化方法(new方法) 项目管理总结 python函数式编程之-装饰器(Decorators) python文件批量处理 Go,互联网时代的C Python推导式演变(Comprehensions) 项目管理感悟 golang学习简单例子 了解GitHub工作流【译】 PHP Socket的使用 Apache 日志文件格式及简单处理 Python脚本--下载合并SAE日志 PHP命名空间及自动加载 基于CSS3实现尖角面包屑 部署Ceilometer到已有环境中 OpenStack Ceilometer Collector代码解读 OpenStack Ceilometer数据存储与API源码解析 OpenStack Ceilometer中的Pipeline机制 OpenStack Ceilometer Compute Agent源码解读 学习Python动态扩展包stevedore 学习Python的ABC模块 Python包管理工具setuptools详解 OpenStack Horizon 中文本地化 WSGI学习 在虚拟机单机部署OpenStack Grizzly 学习使用python打包工具distutils python包工具之间的关系 给OpenStack创建Ubuntu镜像 OpenStack Grizzly Multihost部署文档 为什么使用pip而不是easy_install HTML中meta标签viewpoint的作用 交互式编程-IPython 页面提速之——数据缓存 给OpenStack创建Win7镜像 Ceilometer的命令行使用 部署一个ceilometer-horizon项目 给OpenStack创建Windows XP镜像 几种企业的存储系统 概念模型、逻辑模型、物理模型的区别 五中常见的开源协议整理(BSD,Apache,GPL,LGPL,MIT) OpenStack监控项目Ceilometer的一些术语 VNC和远程桌面的区别 OpenStack Ceilometer项目简介 虚拟化与云计算中KVM,Xen,Qemu的区别和联系 调试和修改OpenStack中的Horizon部分 JavaScript变量作用域 kanyun worker原理 kanyun server服务 在OpenStack中部署kanyun kanyun的api-client命令 sae下的python开发部署和一个简单例子 OpenStack Nova内部机制 PHP可变变量 JS中防止浏览器屏蔽window.open PHP操作Session的原理及提升安全性时的一个问题

标签


golang结构体和包中的类型或基础类型定义方法

2014年03月26日

1、对结构体定义方法

首先看下面这个例子:

package main

import (
    "fmt"
    "math"
)

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
    v := &Vertex{3, 4}
    fmt.Println(v.Abs())
    fmt.Println(v,*v)

    x := Vertex{3, 4}
    fmt.Println(x.Abs())
    fmt.Println(x)   
}

Go 没有类。然而,仍然可以在结构体类型上定义方法。方法接收者 出现在 func 关键字和方法名之间的参数中--- (v *Vertex)

func (v *Vertex) FunName() float64 {
      // 
}

2、对包中的任意类型定义任意方法

对包中的 任意 类型定义任意方法,而不仅仅是针对结构体。不能对来自其他包的类型或基础类型定义方法。----- (f MyFloat) 如下示例:

package main

import (
    "fmt"
    "math"
)

type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

func main() {
    f := MyFloat(-math.Sqrt2)
    fmt.Println(f.Abs())
}

下面用如下这个例子来区二者区别以及用法:

package main

import (
    "fmt"
    "math"
)
// 普通类型
type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

func (f *MyFloat) P() float64{
    if *f < 0 {
        return float64(-*f)
    }
    return float64(*f)
}

// 结构体
type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}


func main() {
    // 基础类型的初始化和调用方式,注意用()而不是{}
    f := MyFloat(-math.Sqrt2)
    fmt.Println(f.Abs(),f.P())

    /* 
    错误调用方式1:
    f1 := &MyFloat(-math.Sqrt2)
    fmt.Println(*f.Abs(),*f.P())

    错误调用方式2:
    f1 := &MyFloat{-math.Sqrt2}
    fmt.Println(*f.Abs(),*f.P())
    错误调用方式3:
    f1 := MyFloat{-math.Sqrt2}
    fmt.Println(f.Abs(),f.P())
    */
    v := &Vertex{3, 4}
    fmt.Println(v, *v,&v,v.Abs())
    v.Scale(5)
    fmt.Println(v, *v,&v,v.Abs())

    v1 := Vertex{6, 7}
    fmt.Println(v1,&v1, v1.Abs())
    v1.Scale(8)
    fmt.Println(v1, v1.Abs())
}
// 输出:
/*
1.4142135623730951 1.4142135623730951
&{3 4} {3 4} 0x10500178 5
&{3 4} {3 4} 0x10500178 5
{6 7} &{6 7} 9.219544457292887
{6 7} 9.219544457292887
*/

注意区别:

func (v *Vertex) Abs() float64 
func (v Vertex) Abs() float64 

3、注意两者区别:

  • func (v *Vertex) Abs() float64 调用方法时传递的是对象的实例的指针,即可改变对象的值;
  • func (v Vertex) Abs() float64 调用方法时传递的是对象的实例的一个副本,即不可改变对象的值;

总结:对象的实例针对数据操作时必须定义为指针的类型,然后才能传递正确的地址,否则v参数只是对象的一个副本,

下面这个实例则可佐证此观点:

package main

import (
    "fmt"
    "math"
)
// 普通类型
type MyFloat float64

func (f MyFloat) Abs()  {
    if f < 0 {
        f = MyFloat(float64(-f))
    }
     f = MyFloat(float64(f))
}

func (f *MyFloat) Abs_1() {
    if *f < 0 {
        *f = MyFloat(float64(-*f))
    }
    *f = MyFloat(float64(*f))
}

// 结构体
type Vertex struct {
    X, Y float64
}

func (v Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}

func (v *Vertex) Scale_1(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}


func main() {
    // 基础类型的初始化和调用方式,注意用()而不是{}
    f := MyFloat(-math.Sqrt2)
    fmt.Println(f, &f)
    f.Abs()
    fmt.Println(f, &f)
    f.Abs_1()
    fmt.Println(f, &f)


    v := &Vertex{3, 4}
    fmt.Println(v, *v,&v)
    v.Scale(5)
    fmt.Println(v, *v,&v)
    v.Scale_1(5)
    fmt.Println(v, *v,&v)

    v1 := Vertex{6, 7}
    fmt.Println(v1,&v1)
    v1.Scale(8)
    fmt.Println(v1, &v1)
    v1.Scale_1(8)
    fmt.Println(v1, &v1)
}
// 输出结果:
/*
-1.4142135623730951 0x10500168
-1.4142135623730951 0x10500168
1.4142135623730951 0x10500168
&{3 4} {3 4} 0x10500188
&{3 4} {3 4} 0x10500188
&{15 20} {15 20} 0x10500188
{6 7} &{6 7}
{6 7} &{6 7}
{48 56} &{48 56}
*/

总结:golang隐式传递指针,但是不隐式定义指针,此坑需同学们注意。


golang-python学习心得
微信公众号:golang-python
个人微信ID:fuhao1121
网址:http://fuhao715.github.io
QQ:243312452
编程学习心得轻松学编程
回复:『 p 』查看python课程回复
回复:『 g 』查看golang课程回复
回复:『 m 』查看项目管理
回复:『 w 』查看其他文章
点击"阅读全文"进入http://fuhao715.github.io