#GO语言面向对象编程之方法(上)#
<font size=5>学过C++或者JAVA的程序员,对于面向对象编程应该是很熟悉的。大家都知道面向对象编程的三大基本特征:封装,继承,多态。在GO语言中,简化了很多面向对象编程的概念,比如 继承,虚函数,构造函数,析构函数,隐藏指针等。对于接触过面向对象编程的人来说,GO语言的面向对象编程更加的简单易懂。</font>
##方法(类)的定义
<font size = 4>在函数声明时,在其名字之前放上一个变量,即是一个方法。这个附加的参数会将该函数附加到这种类型上,即相当于为这种类型定义了一个独占的方法。</font>
package main
import "math"
import "fmt"
type Point struct {
x float64
y float64
}
func TraDistance(p1 Point, p2 Point) float64 {
return math.Hypot(p1.x-p2.x, p1.y-p2.y)
}
func (p1 Point) ObjDistance(p2 Point) float64 {
return math.Hypot(p1.x-p2.x, p1.y-p2.y)
}
func main() {
p1 := Point{10, 20}
p2 := Point{20, 10}
old_len := TraDistance(p1, p2)
new_len := p1.ObjDistance(p2)
fmt.Println("The result of old method is ", old_len)
fmt.Println("The result of OBJ method is ", new_len)
}
<font color = red>在Go语言里,我们为一些简单的数值、字符串、slice、map来定义一些附加行为很方便。方法可以被声明到任意类型,只要不是一个指针或者一个interface。</font>
****
##指针对象
引入指针对象的原因在于GO语言和C语言一样,都是基于值传递的,什么意思哪,就是你调用函数的时候,对对象的值进行了拷贝,所以是没法修改对象内部的值的,看下面的例子:
type Shape struct {
length float64
height float64
weight float64
}
func (s Shape) ChangeHeight(value float64) {
s.height = value
}
triangle := Shape{1, 3, 4}
triangle.ChangeHeight(10)
fmt.Println(triangle.height) //输出3
func (s *Shape) ChangeHeightWithPoint(value float64) {
s.height = value
}
triangle := Shape{1, 3, 4}
//(&triangle).ChangeHeightWithPoint(10)
//triangle.ChangeHeightWithPoint(10)
fmt.Println(triangle.height) //上面两种调用方法都可以改变对象的值
对于第二种为什么两种方法都可以调用哪?因为GO语言帮我们做了隐式转换,当然我们也可以用指针来调用非指针的,就像上面的第triangle.ChangeHeight(10)也可以写成(&triangle).ChangeHeight(10),同样的GO语言也会帮你隐式转换成非指针。
***
##通过嵌入式结构体扩展类型(类似继承)
前面的时候说过结构体的嵌入和匿名函数。我们看下面的一个例子:
type Point struct {
x float64
y float64
}
type Shape struct {
Point
length float64
height float64
weight float64
}
func (p1 Point) ObjDistance(p2 Point) float64 {
return math.Hypot(p1.x-p2.x, p1.y-p2.y)
}
p1 := Point{10, 20}
p2 := Point{20, 10}
triangle := Shape{p1, 1, 3, 4}
len := triangle.ObjDistance(p2)
fmt.Println(len)
Shape是可以直接对Point对象的函数进行调用的,看到这里是不是感觉这就是c++里面的继承,那我们再看下面这个例子:
p1 := Point{10, 20}
p2 := Point{20, 10}
triangle := Shape{p1, 1, 3, 4}
triangle2 := Shape{p2, 1, 3, 4}
fmt.Printf("The point2 value in triangle2 x=%f,y=%f", triangle2.x, triangle2.y)
len := triangle.ObjDistance(triangle2)
这个时候编译程序会有下面的错误:
<font color = red>cannot use triangle2 (type Shape) as type Point in argument to triangle.Point.ObjDistance</font>
对于函数ObjDistance来说,参数Point类型不能用Shape类型,即使Shape类型可以直接访问Point的变量.但对于c++或者java来说,子类是可以作为参数传递的,如下面的代码:
#include<iostream>
using namespace std;
class Parent
{
public:
int x = 10 ,y = 20;
};
class Child : public Parent
{
public:
int m,n;
};
int test(Parent s)
{
cout << s.x <<s.y;
}
int main()
{
Child childObj;
test(childObj);//编译和运行没问题
}
所以GO语言的“继承”并不等同于其它面向对象语言的继承。
***
##方法值和方法表达式
方法的值:
func (p1 Point) ObjDistance(p2 Point) float64 {
return math.Hypot(p1.x-p2.x, p1.y-p2.y)
}
p1 := Point{10, 20}
p2 := Point{20, 10}
p1Func := p1.ObjDistance
p1Func(p2)
方法的表达式:
func (p1 Point) ObjDistance(p2 Point) float64 {
return math.Hypot(p1.x-p2.x, p1.y-p2.y)
}
p1 := Point{10, 20}
p2 := Point{20, 10}
p2Func := Point.ObjDistance
p2Func(p1, p2)
方法的表达式看着比函数多了一个参数,这是因为方法的表达式会把第一个参数作为接收器,后面的参数才是函数的真正参数。
##封装
在C++里面,我们使用public,private,protected关键字来作为变量或者函数的权限设置,但在Go语言中,前面已经说过,GO语言只有大小写的区别,如果想把函数或者变量暴露在外部,那么就首字母大写,相反则小写。</font>
有疑问加站长微信联系(非本文作者))