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.
封装数据和行为
结构体定义
type Employee struct {
Id string
Name string
}
实例创建及初始化
e := Employee{"0","Bob"}
e1 := Employee{Id:"0",Name:"Bob"}
e2 := new(Employee) //注意这里返回的引用/指针,相当于 e:= &Employee{}
e2.Id = "2" //与其他主要编程语言的差异:通过示例的指针访问成员不需要使用 ->
e2.Name = "Lisi"
示例代码
package encapsulation
import "testing"
type Employee struct {
Id string
Name string
Age int
}
func TestCreateEmployee(t *testing.T) {
e := Employee{"0","Bob",20}
e1 := Employee{Name:"Bob",Age:20}
e2 := new(Employee)
e2.Id = "2"
e2.Name = "Rose"
t.Log(e)
t.Log(e1)
t.Log(e1.Id)
t.Log(e2)
t.Logf("e is %T",e)
t.Logf("e2 is %T",e2)
}
输出
=== RUN TestCreateEmployee
--- PASS: TestCreateEmployee (0.00s)
encap_test.go:17: {0 Bob 20}
encap_test.go:18: { Bob 20}
encap_test.go:19:
encap_test.go:20: &{2 Rose 0}
encap_test.go:21: e is encapsulation.Employee
encap_test.go:22: e2 is *encapsulation.Employee
PASS
Process finished with exit code 0
行为(方法)定义
//第一种定义方式在实例对应方法被调用时,实例的成员会进行值复制
func (e Employee) String() string {
return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
}
//通常情况下为了避免内存拷贝我们使用第二种定义方式
func (e *Employee) String() string {
return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
}
示例代码 第二种
func (e *Employee) String() string {
fmt.Printf("Address is %x\n", 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}
fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name))
t.Log(e.String())
}
输出
=== RUN TestStructOperations
Address is c000066370
Address is c000066370
--- PASS: TestStructOperations (0.00s)
encap_test.go:41: ID:0-Name:Bob-Age:20
PASS
Process finished with exit code 0
第一种
func (e Employee) String() string {
fmt.Printf("Address is %x\n", 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}
fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name))
t.Log(e.String())
}
输出
=== RUN TestStructOperations
Address is c000066370
Address is c0000b6010
--- PASS: TestStructOperations (0.00s)
encap_test.go:42: ID:0-Name:Bob-Age:20
PASS
Process finished with exit code 0
可以看出两份代码的输出结果是不一样的,第二种方式内存地址并没有改变,而第一种方式的内存地址是改变了的,第一种方法因为数据的复制,就会引起多余的开销,小心使用
示例代码请访问: github.com/wenjianzhan…