Golang List 源码解析

List

golang 里的 List (在container/list包当中) 是一个特殊的双向链表.

每一个元素会直接指向链表的"哨兵节点".

数据结构:

// 链表元素 
type Element struct {
	// 链表的元素中的下一个和上一个指针.
    // 为了简化实现, 内部将列表 l 实现为环, 这样 &l.root 既是最后一个列表元素( l.Back() )的下一个元素,
    // 也是第一个列表元素( l.Front() ).
	next, prev *Element

	// 该元素所属的链表
	list *List

	// 元素存储的内容
	Value interface{}
}

// List代表一个双向链表.
// List的零值是可以使用的空列表.
type List struct {
	root Element // 链表的哨兵元素, 只有 &root, root.prev, root.next 被使用
	len  int     // 链表的长度, 不包括哨兵元素
}
  • 链表初始化
func (l *List) Init() *List {
	// 双向链表, 都指向自己
	l.root.next = &l.root
	l.root.prev = &l.root
	
	l.len = 0
	return l
}
func (l *List) lazyInit() {
	// l.root.next 为 nil, 则说明链表没有初始化, 因为初始化之后, l.root.next 为 &l.root.
	if l.root.next == nil {
		l.Init()
	}
}
  • 插入数据
// 在 at 后面插入 e
/**
before:

       ->      ->
    X      at      Y
       <-      <- 
 
---------------------------------
 
after:
       ->      ->      ->
    X      at       e       Y
       <-      <-      <-
**/
func (l *List) insert(e, at *Element) *Element {
	// 保存 at 的下一个元素 Y
	n := at.next
	
	// 调整 at 的 next,  e 的 prev
	at.next = e
	e.prev = at
	
	// 调整 e 的 next, n 的 prev
	e.next = n
	n.prev = e
	
	// 设置 e 所属的列表, 增加列表长度
	e.list = l
	l.len++
	return e
}
  • 删除数据
// 删除元素 e
/**
before:
        
       ->      ->
    X      e       Y
       <-      <- 
 
---------------------------------

after:
       ->      
    X      Y   
       <-    
**/

func (l *List) remove(e *Element) *Element {
    // 调整 e 前面元素的 next 和 e 后面元素的 prev
	e.prev.next = e.next
	e.next.prev = e.prev
	
	// 调整 e 元素本身的前后指向
	e.next = nil // avoid memory leaks
	e.prev = nil // avoid memory leaks
	
	// 移除 e 的 list, 减少元素数量
	e.list = nil
	l.len--
	return e
}
  • 移动元素
// 将元素 e 移动到 at 后面, 然后返回 e
/**
before:
        
       ->      ->            ->      ->
    X      e       Y .... U      at      V
       <-      <-            <-      <-
 
---------------------------------

after:
       ->     ->      ->             ->
    X      e      at       Y .... U      V
       <-     <-      <-             <-
**/

// 相当于先删除 e, 然后将 e 添加到 at 后面
func (l *List) move(e, at *Element) *Element {
	if e == at {
		return e
	}
	// 删除元素 e
	e.prev.next = e.next
	e.next.prev = e.prev

    // 添加元素 e 
	n := at.next
	
	at.next = e
	e.prev = at
	e.next = n
	n.prev = e

	return e
}
  • 合并 list
func (l *List) PushBackList(other *List) {
	l.lazyInit()
	// 初始化的时候, e 是 other 的第一个元素
	// 然后每次将 e 的下一个元素, 插入到 l 的后面
	for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
		l.insertValue(e.Value, l.root.prev)
	}
}
  • 移动元素位置
// 将 e 移动到 mark 的后面
func (l *List) MoveAfter(e, mark *Element) {
	// e.list != l 或者 mark.list != l, 说明 e 或 mark 不属于当前的 list
	// e == mark 说明 e 和 mark 是同一个元素.
	if e.list != l || e == mark || mark.list != l {
		return
	}
	l.move(e, mark)
}
// 将 e 移动到最前面.  <=> 将 e 移动 l.root 的后面
func (l *List) MoveToFront(e *Element) {
	// l.root.next == e, 说明 e 已经是第一个元素了.
	if e.list != l || l.root.next == e {
		return
	}
	l.move(e, &l.root)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Golang 1.18版本的Transport源码是一个比较复杂的包,涉及到HTTP客户端和服务器之间的网络传输。我将尝试给出一个简单的解析,帮助你理解其中的关键部分。 在源码中,Transport包含一个名为Transport的结构体类型。这个结构体有许多字段和方法,用来管理HTTP请求和响应的传输过程。 首先,Transport结构体中的字段有: 1. Proxy:代理服务器的URL,用于将请求发送到代理服务器。 2. DialContext:一个函数类型,用于建立与目标服务器的连接。 3. TLSClientConfig:用于配置TLS(Transport Layer Security)的客户端配置。 4. ForceAttemptHTTP2:一个布尔值,表示是否强制使用HTTP/2协议进行传输。 5. MaxIdleConns:最大空闲连接数。 6. IdleConnTimeout:空闲连接超时时间。 7. ExpectContinueTimeout:等待"Expect: 100-continue"响应的超时时间。 8. MaxResponseHeaderBytes:最大响应头字节数。 除了这些字段外,Transport还有一些方法,其中最重要的是RoundTrip方法。这个方法负责执行HTTP请求并返回响应。它接收一个指向Request结构体的指针作为参数,并返回一个指向Response结构体的指针。 RoundTrip方法内部会根据请求的URL、代理设置、TLS配置等信息建立连接,并发送请求。它还会处理重定向、错误处理、连接复用等逻辑。最终,它将获取到的响应封装在Response结构体中,并返回给调用者。 除了RoundTrip方法,Transport还有其他一些辅助方法,用于管理连接池、设置代理、处理错误等。 总体来说,Transport源码的实现非常复杂,涉及到了很多底层的网络和协议细节。如果你希望深入了解源码的具体实现细节,我建议你仔细阅读源代码,并查阅相关的文档和资料。 希望这个简要的解析能对你有所帮助!如果你有更多关于Transport源码的具体问题,欢迎进一步提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值