第六章:结构体与接口
6.1 结构体
结构体基础
package main
import "fmt"
// Person 人员结构体
type Person struct {
Name string
Age int
City string
}
// Employee 员工结构体(嵌入Person)
type Employee struct {
Person // 匿名字段(嵌入)
ID int
Salary float64
Department string
}
func main() {
// 结构体初始化
p1 := Person{
Name: "张三",
Age: 25,
City: "北京",
}
fmt.Printf("p1: %+v\\n", p1)
// 按顺序初始化
p2 := Person{"李四", 30, "上海"}
fmt.Printf("p2: %+v\\n", p2)
// 使用new创建
p3 := new(Person)
p3.Name = "王五"
p3.Age = 28
p3.City = "广州"
fmt.Printf("p3: %+v\\n", p3)
// 访问字段
fmt.Printf("姓名: %s\\n", p1.Name)
fmt.Printf("年龄: %d\\n", p1.Age)
// 修改字段
p1.Age = 26
fmt.Printf("修改后年龄: %d\\n", p1.Age)
// 结构体嵌入
emp := Employee{
Person: Person{
Name: "赵六",
Age: 35,
City: "深圳",
},
ID: 1001,
Salary: 15000,
Department: "技术部",
}
// 访问嵌入字段
fmt.Printf("\\n员工信息:\\n")
fmt.Printf("姓名: %s\\n", emp.Name) // 直接访问Person的字段
fmt.Printf("年龄: %d\\n", emp.Age)
fmt.Printf("城市: %s\\n", emp.City)
fmt.Printf("工号: %d\\n", emp.ID)
fmt.Printf("薪资: %.2f\\n", emp.Salary)
fmt.Printf("部门: %s\\n", emp.Department)
}
结构体方法
package main
import (
"fmt"
"math"
)
// Point 点结构体
type Point struct {
X, Y float64
}
// 值接收者方法
func (p Point) Distance() float64 {
return math.Sqrt(p.X*p.X + p.Y*p.Y)
}
func (p Point) String() string {
return fmt.Sprintf("(%.2f, %.2f)", p.X, p.Y)
}
// 指针接收者方法
func (p *Point) Translate(dx, dy float64) {
p.X += dx
p.Y += dy
}
// 圆形结构体
type Circle struct {
Center Point
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Circumference() float64 {
return 2 * math.Pi * c.Radius
}
func (c Circle) Contains(p Point) bool {
dx := p.X – c.Center.X
dy := p.Y – c.Center.Y
return math.Sqrt(dx*dx+dy*dy) <= c.Radius
}
// 矩形结构体
type Rectangle struct {
TopLeft Point
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func (r Rectangle) Contains(p Point) bool {
return p.X >= r.TopLeft.X &&
p.X <= r.TopLeft.X+r.Width &&
p.Y >= r.TopLeft.Y &&
p.Y <= r.TopLeft.Y+r.Height
}
func main() {
// Point方法
p := Point{3, 4}
fmt.Printf("点: %s\\n", p.String())
fmt.Printf("到原点距离: %.2f\\n", p.Distance())
p.Translate(1, 1)
fmt.Printf("平移后: %s\\n", p.String())
fmt.Printf("到原点距离: %.2f\\n", p.Distance())
// Circle方法
c := Circle{Center: Point{0, 0}, Radius: 5}
fmt.Printf("\\n圆心: %s\\n", c.Center.String())
fmt.Printf("半径: %.2f\\n", c.Radius)
fmt.Printf("面积: %.2f\\n", c.Area())
fmt.Printf("周长: %.2f\\n", c.Circumference())
p1 := Point{3, 4}
p2 := Point{6, 8}
fmt.Printf("点%s在圆内: %v\\n", p1.String(), c.Contains(p1))
fmt.Printf("点%s在圆内: %v\\n", p2.String(), c.Contains(p2))
// Rectangle方法
r := Rectangle{
TopLeft: Point{0, 0},
Width: 10,
Height: 5,
}
fmt.Printf("\\n矩形面积: %.2f\\n", r.Area())
fmt.Printf("矩形周长: %.2f\\n", r.Perimeter())
p3 := Point{5, 2}
p4 := Point{15, 2}
fmt.Printf("点%s在矩形内: %v\\n", p3.String(), r.Contains(p3))
fmt.Printf("点%s在矩形内: %v\\n", p4.String(), r.Contains(p4))
}
6.2 接口
接口基础
package main
import (
"fmt"
"math"
)
// Shape 形状接口
type Shape interface {
Area() float64
Perimeter() float64
}
// Stringer 字符串化接口
type Stringer interface {
String() string
}
// Circle 圆形
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
func (c Circle) String() string {
return fmt.Sprintf("圆形(半径=%.2f)", c.Radius)
}
// Rectangle 矩形
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func (r Rectangle) String() string {
return fmt.Sprintf("矩形(宽=%.2f, 高=%.2f)", r.Width, r.Height)
}
// Triangle 三角形
type Triangle struct {
A, B, C float64 // 三边长
}
func (t Triangle) Area() float64 {
s := (t.A + t.B + t.C) / 2
return math.Sqrt(s * (s – t.A) * (s – t.B) * (s – t.C))
}
func (t Triangle) Perimeter() float64 {
return t.A + t.B + t.C
}
func (t Triangle) String() string {
return fmt.Sprintf("三角形(三边=%.2f,%.2f,%.2f)", t.A, t.B, t.C)
}
// PrintShapeInfo 打印形状信息
func PrintShapeInfo(s Shape) {
fmt.Printf("形状: %s\\n", s.String())
fmt.Printf("面积: %.2f\\n", s.Area())
fmt.Printf("周长: %.2f\\n", s.Perimeter())
}
func main() {
// 创建不同形状
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 10, Height: 5},
Triangle{A: 3, B: 4, C: 5},
}
// 遍历并打印信息
for _, shape := range shapes {
PrintShapeInfo(shape)
fmt.Println()
}
// 接口类型断言
fmt.Println("类型断言:")
for _, shape := range shapes {
switch v := shape.(type) {
case Circle:
fmt.Printf("这是一个圆形,半径: %.2f\\n", v.Radius)
case Rectangle:
fmt.Printf("这是一个矩形,宽: %.2f, 高: %.2f\\n", v.Width, v.Height)
case Triangle:
fmt.Printf("这是一个三角形,三边: %.2f, %.2f, %.2f\\n", v.A, v.B, v.C)
}
}
}
空接口与类型断言
package main
import "fmt"
// 空接口可以存储任意类型
func describe(i interface{}) {
fmt.Printf("类型: %T, 值: %v\\n", i, i)
}
func main() {
// 空接口存储不同类型
describe(42)
describe("hello")
describe(3.14)
describe(true)
describe([]int{1, 2, 3})
describe(map[string]int{"a": 1})
// 类型断言
var i interface{} = "hello"
// 方式1: 直接断言(如果类型不匹配会panic)
s := i.(string)
fmt.Println(s)
// 方式2: 安全断言(返回值和ok)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
// 类型switch
values := []interface{}{42, "hello", 3.14, true, []int{1, 2, 3}}
for _, v := range values {
switch v := v.(type) {
case int:
fmt.Printf("int: %d\\n", v)
case string:
fmt.Printf("string: %s\\n", v)
case float64:
fmt.Printf("float64: %.2f\\n", v)
case bool:
fmt.Printf("bool: %v\\n", v)
case []int:
fmt.Printf("[]int: %v\\n", v)
default:
fmt.Printf("未知类型: %T\\n", v)
}
}
}
接口组合
package main
import "fmt"
// Reader 读取接口
type Reader interface {
Read(p []byte) (n int, err error)
}
// Writer 写入接口
type Writer interface {
Write(p []byte) (n int, err error)
}
// ReadWriter 读写接口(组合)
type ReadWriter interface {
Reader
Writer
}
// Closer 关闭接口
type Closer interface {
Close() error
}
// ReadWriteCloser 读写关闭接口
type ReadWriteCloser interface {
Reader
Writer
Closer
}
// File 文件结构体
type File struct {
Name string
Content []byte
Pos int
}
func (f *File) Read(p []byte) (n int, err error) {
if f.Pos >= len(f.Content) {
return 0, fmt.Errorf("EOF")
}
n = copy(p, f.Content[f.Pos:])
f.Pos += n
return n, nil
}
func (f *File) Write(p []byte) (n int, err error) {
f.Content = append(f.Content, p…)
return len(p), nil
}
func (f *File) Close() error {
fmt.Printf("文件 %s 已关闭\\n", f.Name)
return nil
}
func (f *File) String() string {
return fmt.Sprintf("File(%s, %d bytes)", f.Name, len(f.Content))
}
// ProcessReaderWriter 处理读写
func ProcessReaderWriter(rw ReadWriter) error {
// 写入数据
data := []byte("Hello, Go!")
_, err := rw.Write(data)
if err != nil {
return err
}
// 读取数据
buf := make([]byte, 100)
n, err := rw.Read(buf)
if err != nil {
return err
}
fmt.Printf("读取的数据: %s\\n", buf[:n])
return nil
}
func main() {
// 创建文件
f := &File{Name: "test.txt"}
// 使用接口
var rwc ReadWriteCloser = f
// 写入数据
data := []byte("Hello, World!")
n, err := rwc.Write(data)
if err != nil {
fmt.Println("写入错误:", err)
} else {
fmt.Printf("写入了 %d 字节\\n", n)
}
// 读取数据
buf := make([]byte, 100)
n, err = rwc.Read(buf)
if err != nil {
fmt.Println("读取错误:", err)
} else {
fmt.Printf("读取了 %d 字节: %s\\n", n, buf[:n])
}
// 关闭文件
rwc.Close()
// 使用ReadWriter接口
fmt.Println("\\n使用ReadWriter接口:")
ProcessReaderWriter(f)
}
6.3 实战案例:图形计算器
package main
import (
"fmt"
"math"
"strings"
)
// Shape 形状接口
type Shape interface {
Area() float64
Perimeter() float64
Name() string
}
// Circle 圆形
type Circle struct {
Radius float64
}
func NewCircle(radius float64) *Circle {
return &Circle{Radius: radius}
}
func (c *Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c *Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
func (c *Circle) Name() string {
return "圆形"
}
func (c *Circle) String() string {
return fmt.Sprintf("%s(半径=%.2f)", c.Name(), c.Radius)
}
// Rectangle 矩形
type Rectangle struct {
Width, Height float64
}
func NewRectangle(width, height float64) *Rectangle {
return &Rectangle{Width: width, Height: height}
}
func (r *Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r *Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func (r *Rectangle) Name() string {
return "矩形"
}
func (r *Rectangle) String() string {
return fmt.Sprintf("%s(宽=%.2f, 高=%.2f)", r.Name(), r.Width, r.Height)
}
// Square 正方形
type Square struct {
Side float64
}
func NewSquare(side float64) *Square {
return &Square{Side: side}
}
func (s *Square) Area() float64 {
return s.Side * s.Side
}
func (s *Square) Perimeter() float64 {
return 4 * s.Side
}
func (s *Square) Name() string {
return "正方形"
}
func (s *Square) String() string {
return fmt.Sprintf("%s(边长=%.2f)", s.Name(), s.Side)
}
// Triangle 三角形
type Triangle struct {
A, B, C float64
}
func NewTriangle(a, b, c float64) *Triangle {
return &Triangle{A: a, B: b, C: c}
}
func (t *Triangle) Area() float64 {
s := (t.A + t.B + t.C) / 2
return math.Sqrt(s * (s – t.A) * (s – t.B) * (s – t.C))
}
func (t *Triangle) Perimeter() float64 {
return t.A + t.B + t.C
}
func (t *Triangle) Name() string {
return "三角形"
}
func (t *Triangle) String() string {
return fmt.Sprintf("%s(三边=%.2f,%.2f,%.2f)", t.Name(), t.A, t.B, t.C)
}
// ShapeCalculator 图形计算器
type ShapeCalculator struct {
Shapes []Shape
}
func NewShapeCalculator() *ShapeCalculator {
return &ShapeCalculator{
Shapes: make([]Shape, 0),
}
}
func (sc *ShapeCalculator) AddShape(shape Shape) {
sc.Shapes = append(sc.Shapes, shape)
}
func (sc *ShapeCalculator) TotalArea() float64 {
total := 0.0
for _, shape := range sc.Shapes {
total += shape.Area()
}
return total
}
func (sc *ShapeCalculator) TotalPerimeter() float64 {
total := 0.0
for _, shape := range sc.Shapes {
total += shape.Perimeter()
}
return total
}
func (sc *ShapeCalculator) LargestShape() Shape {
if len(sc.Shapes) == 0 {
return nil
}
largest := sc.Shapes[0]
for _, shape := range sc.Shapes[1:] {
if shape.Area() > largest.Area() {
largest = shape
}
}
return largest
}
func (sc *ShapeCalculator) PrintReport() {
fmt.Println(strings.Repeat("=", 60))
fmt.Println("图形计算器报告")
fmt.Println(strings.Repeat("=", 60))
for i, shape := range sc.Shapes {
fmt.Printf("\\n%d. %s\\n", i+1, shape.String())
fmt.Printf(" 面积: %.2f\\n", shape.Area())
fmt.Printf(" 周长: %.2f\\n", shape.Perimeter())
}
fmt.Println("\\n" + strings.Repeat("-", 60))
fmt.Printf("图形总数: %d\\n", len(sc.Shapes))
fmt.Printf("总面积: %.2f\\n", sc.TotalArea())
fmt.Printf("总周长: %.2f\\n", sc.TotalPerimeter())
if largest := sc.LargestShape(); largest != nil {
fmt.Printf("最大图形: %s (面积: %.2f)\\n", largest.String(), largest.Area())
}
fmt.Println(strings.Repeat("=", 60))
}
func main() {
// 创建计算器
calc := NewShapeCalculator()
// 添加图形
calc.AddShape(NewCircle(5))
calc.AddShape(NewRectangle(10, 5))
calc.AddShape(NewSquare(7))
calc.AddShape(NewTriangle(3, 4, 5))
calc.AddShape(NewCircle(3))
calc.AddShape(NewRectangle(8, 6))
// 打印报告
calc.PrintReport()
// 按类型统计
fmt.Println("\\n按类型统计:")
typeCount := make(map[string]int)
typeArea := make(map[string]float64)
for _, shape := range calc.Shapes {
name := shape.Name()
typeCount[name]++
typeArea[name] += shape.Area()
}
for name, count := range typeCount {
fmt.Printf("%s: %d个, 总面积: %.2f\\n", name, count, typeArea[name])
}
}





