Skip to content

Sutdown/Geecache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

在 Go 语言中,类型断言和隐式类型接口是处理接口和类型转换的两个重要机制。它们在 Go 的类型系统中扮演了关键角色。下面是对这两个概念的详细介绍。

1. 类型断言(Type Assertion)

类型断言允许你检验一个接口值的具体类型并进行类型转换。语法如下:

value, ok := interfaceValue.(ConcreteType)
  • interfaceValue 是你要进行断言的接口值。
  • ConcreteType 是你期望的具体类型。
  • value 是转换后的具体类型值。
  • ok 是一个布尔值,表示断言是否成功。

示例

假设有一个接口 Shape 和具体类型 CircleRectangle

package main
import (
    "fmt"
)

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}
func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

type Rectangle struct {
    Width, Height float64
}
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func printArea(s Shape) {
    // 使用类型断言来检查具体类型
    if circle, ok := s.(Circle); ok {
        fmt.Printf("Circle area: %f\n", circle.Area())
    } else if rectangle, ok := s.(Rectangle); ok {
        fmt.Printf("Rectangle area: %f\n", rectangle.Area())
    } else {
        fmt.Println("Unknown shape")
    }
}

func main() {
    c := Circle{Radius: 5}
    r := Rectangle{Width: 4, Height: 3}

    printArea(c)
    printArea(r)
}

在上面的代码中,printArea 函数通过类型断言检查 Shape 接口值的具体类型,并根据具体类型调用相应的方法。

2. 隐式类型接口(Implicit Interface)

Go 语言的接口是隐式实现的。也就是说,一个类型只要实现了接口所需的方法,就自动实现了该接口,而不需要显式地声明它实现了该接口。这与许多其他语言中需要显式实现接口的方式不同。

示例

继续使用之前的例子:

package main

import (
    "fmt"
)

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}
func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

func main() {
    var s Shape
    s = Circle{Radius: 5}
    fmt.Println("Area of Circle:", s.Area())
}

在上面的代码中,Circle 类型自动实现了 Shape 接口,因为 Circle 类型定义了 Area 方法。这种方式使得接口的使用更加灵活和自然。你不需要在 Circle 类型中显式声明它实现了 Shape 接口,只要它实现了接口中的所有方法,就可以被视为实现了该接口。

总结

  • 类型断言 允许你在运行时检查接口值的具体类型,并将其转换为具体类型。它在处理多态接口时非常有用。
  • 隐式类型接口 使得类型的实现变得更加灵活。一个类型只要实现了接口的所有方法,就自动实现了该接口,无需显式声明。

这两个机制使得 Go 的类型系统既灵活又强大,允许你写出简洁而强大的代码。

在 Go 语言中,除了类型断言和隐式接口,还有一些其他机制用于处理接口和类型转换。以下是这些机制的详细说明:

1. 类型转换(Type Conversion)

类型转换允许你将一个值转换为另一种类型。与类型断言不同,类型转换通常用于处理相同基础类型但不同定义的类型。

2. 空接口(Empty Interface)

空接口 interface{} 是 Go 语言中最通用的接口类型,它可以保存任何类型的值,因为所有类型都实现了空接口。空接口常用于处理不确定类型的值或函数参数。

示例

package main

import "fmt"

func printValue(v interface{}) {
    fmt.Println(v)
}

func main() {
    printValue(123)       // 打印整型值
    printValue("hello")   // 打印字符串值
    printValue(3.14)      // 打印浮点值
}

3. 类型转换和类型断言结合使用

在处理接口时,你可能需要将接口值转换为具体类型以访问具体的方法。你可以先进行类型断言,然后再进行类型转换。

示例

package main

import (
    "fmt"
)

type Printer interface {
    Print()
}

type Document struct {
    Name string
}
func (d Document) Print() {
    fmt.Println("Printing document:", d.Name)
}

func printDoc(p Printer) {
    if doc, ok := p.(Document); ok {
        doc.Print()
    } else {
        fmt.Println("Not a Document")
    }
}

func main() {
    d := Document{Name: "Report"}
    printDoc(d)
}

在这个例子中,我们使用了类型断言来检查接口 Printer 是否包含 Document 类型的值。如果是,我们就可以调用 Document 类型的方法。

4. 类型选择(Type Switch)

类型选择是一种扩展的类型断言,用于在运行时根据接口值的具体类型执行不同的代码。

语法

switch v := interfaceValue.(type) {
case ConcreteType1:
    // handle ConcreteType1
case ConcreteType2:
    // handle ConcreteType2
default:
    // handle unknown types
}

示例

package main

import (
    "fmt"
)

func describe(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Println("int:", v)
    case string:
        fmt.Println("string:", v)
    default:
        fmt.Println("unknown type")
    }
}

func main() {
    describe(42)
    describe("hello")
    describe(3.14)
}

在这个例子中,describe 函数根据接口值的具体类型打印不同的消息。

5. 接口组合(Interface Composition)

接口组合允许你通过组合多个接口来创建新的接口。这种方式使得你可以将多个行为组合在一起形成复杂的接口类型。

示例

package main

import "fmt"

type Reader interface {
    Read()
}
type Writer interface {
    Write()
}
type ReadWriter interface {
    Reader
    Writer
}

type MyStruct struct{}

func (m MyStruct) Read() {
    fmt.Println("Reading")
}

func (m MyStruct) Write() {
    fmt.Println("Writing")
}

func main() {
    var rw ReadWriter = MyStruct{}
    rw.Read()
    rw.Write()
}

在这个例子中,ReadWriter 接口组合了 ReaderWriter 接口。MyStruct 类型实现了这两个接口,因此也实现了 ReadWriter 接口。

总结

  • 类型转换:将一个值转换为另一种类型,通常用于不同定义的类型之间的转换。
  • 空接口interface{} 可以存储任何类型的值,是处理不确定类型的通用机制。
  • 类型断言:检查和转换接口值的具体类型。
  • 类型选择:在运行时根据接口值的具体类型执行不同的代码。
  • 接口组合:通过组合多个接口来创建新的接口类型,实现更复杂的行为。

这些机制为 Go 语言中的接口和类型转换提供了强大的功能,使得代码的灵活性和可扩展性大大提高。

Geecache

分布式缓存是什么?为什么要用分布式缓存?简单介绍一下这个项目。

HTTP跨节点缓存数据共享怎么实现?并发怎么实现?缓存穿透是如何发生,如何实现?

一致性哈希是什么?如何做到支持节点的自动扩展的?

如何做到对缓存节点的动态选择和数据获取的。

分布式缓存的话,

需要考虑资源控制,淘汰策略,并发,分布式节点通信等各个方面之间的问题

采用LRU淘汰策略,淘汰最近最少使用的,维护一个双向链表,维护一个map容器

并发的话,主要是利用互斥锁实现,在读写变量的前后加锁,解锁。缓存值采用的是只读数据结构

核心

    
接收 key --> 检查是否被缓存 -----> 返回缓存值 ⑴
                |  否                         是
                |-----> 是否应当从远程节点获取 -----> 与远程节点交互 --> 返回缓存值 ⑵
                            |  否
                            |-----> 调用`回调函数`,获取值并添加到缓存 --> 返回缓存值 ⑶

一致性哈希:设置了一个环。

环上有以及存在的节点,每次向其中添加值,顺时针最近的节点就是应该选取的节点,同时为了避免数据倾斜,引入虚拟节点,扩充了节点的数量。

缓存穿透:查询一个不存在的数据

实现了一个singleflght的包,一个相同的请求无论发送多少次,最后只会通过设置Group和call,发起请求时,

protobuf在节点间通信时,编码报文,提高效率,同时也会对发送前报文,发送后报文编码解码,get的参数做一定针对修改后的报文的更改。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published