ch15、面向对象编程-行为的定义和实现

Is Go an object-oriented language?

Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of “interface” in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing. Moreover, methods in Go are more general than in C++ or Java: they can be defined for any sort of data, even built-in types such as plain, “unboxed” integers. They are not restricted to structs (classes).
Also, the lack of a type hierarchy makes “objects” in Go feel much more lightweight than in languages such as C++ or Java.
Go语言的FQA页面:Frequently Asked Questions (FAQ) - The Go Programming Language?
1、封装数据和行为(方法)Go语言封装数据:
/*type Name struct {}*/package encapsulationtype Employee struct {IdstringName stringAgeint}数据的初始化:
package encapsulationimport "testing"type Employee struct {IdstringName stringAgeint}func TestCreateEmployeeObj(t *testing.T) {// 方法一e := Employee{"0", "Bob", 20}// 方法二e1 := Employee{Name: "Mike", Age: 30}// 方法三 , 使用new关键字(返回的是指针 , 使用.访问数据)e2 := new(Employee) // 返回指针e2.Id = "2"e2.Name = "Rose"e2.Age = 22t.Log(e)t.Log(e1)t.Log(e1.Id)t.Log(e2)t.Logf("e is %T", e)t.Logf("e2 is %T", e2)}【ch15、面向对象编程-行为的定义和实现】封装行为(方法):
package error_test2import ("errors""testing")func GetFibonacci(n int) ([]int, error) {if n < 2 || n > 100 {// 设置error返回10return nil, errors.New("n's should be in [2,100]")}fibList := []int{1, 1}for i := 2; i < n; i++ {fibList = Append(fibList, fibList[i-2]+fibList[i-1])}return fibList, nil}func TestGetFibonacci(t *testing.T) {if v, err := GetFibonacci(-10); err != nil {t.Error(err)} else {t.Log(v)}}package encapsulationimport ("fmt""testing""unsafe")type Employee struct {IdstringName stringAgeint}// 第一种定义方式在实例对应方法被调用时 , 实例的成员会进行值复制func (e Employee) String() string {fmt.Printf("func object Address is %xn", unsafe.Pointer(&e.Name))return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)}func TestStructOperations(t *testing.T) {e := Employee{"0", "Bob", 20}e2 := new(Employee) // 返回指针e2.Id = "2"e2.Name = "Rose"e2.Age = 22fmt.Printf("e Address is %xn", unsafe.Pointer(&e.Name))fmt.Printf("e2 Address is %xn", unsafe.Pointer(&e2.Name))t.Log(e.String())t.Log(e2.String())}/*输出的地址不一样 , 说明是值复制*/第二种定义方式定义实例对象为指针(go都是值传递 , 但复制的是指针 , 指向的是同一块内存)
通常情况下为了避免内存拷贝 , 使用第二种方式
package encapsulationimport ("fmt""testing""unsafe")type Employee struct {IdstringName stringAgeint}// 通常情况下为了避免内存拷贝我们使用第二种定义方式(指针 , go都是值传递 , 但复制的是指针 , 但指向的是同一个)func (e *Employee) String() string {fmt.Printf("func object Address is %xn", unsafe.Pointer(&e.Name))return fmt.Sprintf("ID:%s/Name:%s/Age:%d", e.Id, e.Name, e.Age)}func TestStructOperations(t *testing.T) {e := Employee{"0", "Bob", 20}e2 := new(Employee) // 返回指针e2.Id = "2"e2.Name = "Rose"e2.Age = 22fmt.Printf("e Address is %xn", unsafe.Pointer(&e.Name))fmt.Printf("e2 Address is %xn", unsafe.Pointer(&e2.Name))t.Log(e.String())t.Log(e2.String())}/*输出地址一样 , 说明指向的是同一块内存*/思考:第二种方式是否协程或线程安全?即:假如修改了结构体里边的元素值 , 会污染到其他线程或者协程吗?
2、结构体类型转换属性名、属性类型、属性个数、排列顺序都是类型组成部分
  • 只有属性名、属性类型、属性个数、排列顺序都相同的结构体类型才能转换(且是强制转换)
package mainimport "fmt"func main() {type Person1 struct {name stringageint}type Person2 struct {name stringageint}type Person3 struct {ageintname string}type Person4 struct {nmstringage int}type Person5 struct {name stringagestring}type Person6 struct {namestringageintgender string}var p1 Person1 = Person1{"lnj", 33}var p2 Person2// 类型名称不一样不能直接赋值(Person1、Person2)//p2 = p1// 虽然类型名称不一样, 但是两个类型中的`属性名称`、`属性类型`、`属性个数`、`排列顺序`都一样,所以可以强制转换p2 = Person2(p1)fmt.Println(p2)// 两个结构体类型中的`属性名称`、`属性类型`、`属性个数`都一样,但是`排列顺序`不一样,所以不能强制转换//var p3 Person3//p3 = Person3(p1)//fmt.Println(p3)// 两个结构体类型中的`属性类型`、`属性个数`、`排列顺序`都一样,但是`属性名称`不一样,所以不能强制转换//var p4 Person4//p4 = Person4(p1)//fmt.Println(p4)// 两个结构体类型中的`属性名称`、`属性个数`、`排列顺序`都一样,但是`属性类型`不一样,所以不能强制转换//var p5 Person5//p5 = Person5(p1)//fmt.Println(p5)// 两个结构体类型中的`属性名称`、`属性类型`、`排列顺序`都一样,但是`属性个数`不一样,所以不能强制转换//var p6 Person6//p6 = Person6(p1)//fmt.Println(p6)}


推荐阅读