Iterator-Generator详解

news2024/11/25 7:08:37

1 迭代器可迭代对象

2 原生的迭代器对象

3 自定义类的迭代器

4 生成器理解和作用

5 自定义生成器方案

6 异步处理方案解析

迭代器-JavaScript中迭代器(了解)

给某个数组专门添加一个迭代器的代码。

 const names = ["abc", "cba", "nba"]
    
    // 给数组names创建一个迭代器(迭代器: names的迭代器)
    let index = 0
    const namesIterator = {
      next: function() {
        // done: Boolean
        // value: 具体值/undefined
        if (index < names.length) {
          return { done: false, value: names[index++] }
        } else {
          return { done: true }
        }
      }
    }

    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())

    // 数组nums
    const nums = [100, 24, 55, 66, 86]
    
    let indexNum = 0
    const numsIterator = {
      next: function() {
        // done: Boolean
        // value: 具体值/undefined
        if (indexNum < nums.length) {
          return { done: false, value: nums[indexNum++] }
        } else {
          return { done: true }
        }
      }
    }

迭代器-为数组创建迭代器(了解)

给任意数组做的迭代器。

 const names = ["abc", "cba", "nba"]
    const nums = [100, 24, 55, 66, 86]

    // 封装一个函数
    function createArrayIterator(arr) {
      let index = 0
      return {
        next: function() {
          if (index < arr.length) {
            return { done: false, value: arr[index++] }
          } else {
            return { done: true }
          }
        }
      }
    }

    const namesIterator = createArrayIterator(names)
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())

    const numsIterator = createArrayIterator(nums)
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())

可迭代对象-创建可迭代对象(了解)

可迭代对象和迭代器是两个东西,迭代器是可迭代对象里面的方法,这样子的对象是可通过迭代器来迭代的,可以通过迭代来获取value值。

 // 将infos变成一个可迭代对象
    /*
      1.必须实现一个特定的函数: [Symbol.iterator]
      2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
    */
    const infos = {
      friends: ["kobe", "james", "curry"],
      [Symbol.iterator]: function() {
        let index = 0
        const infosIterator = {
          next: function() {
            // done: Boolean
            // value: 具体值/undefined
            if (index < infos.friends.length) {
              return { done: false, value: infos.friends[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return infosIterator
      }
    }

    // 给infos创建一个迭代器, 迭代infos中的friends
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())


    // 可迭代对象必然具备下面的特点
    // const iterator = infos[Symbol.iterator]()
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())

    // 可迭对象可以进行for of操作
    for (const item of infos) {
      console.log(item)
    }


    // 可迭代对象必然有一个[Symbol.iterator]函数
    // 数组是一个可迭代对象
    const students = ["张三", "李四", "王五"]
    console.log(students[Symbol.iterator])
    const studentIterator = students[Symbol.iterator]()
    console.log(studentIterator.next())
    console.log(studentIterator.next())
    console.log(studentIterator.next())
    console.log(studentIterator.next())

可迭代对象-可迭代对象优化(了解)

1

   // 将infos变成一个可迭代对象
    /*
      1.必须实现一个特定的函数: [Symbol.iterator]
      2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
    */
   // 1.迭代infos中friends
    // const infos = {
    //   friends: ["kobe", "james", "curry"],
    //   [Symbol.iterator]: function() {
    //     let index = 0
    //     const infosIterator = {
    //       next: () => {
    //         if (index < this.friends.length) {
    //           return { done: false, value: this.friends[index++] }
    //         } else {
    //           return { done: true }
    //         }
    //       }
    //     }
    //     return infosIterator
    //   }
    // }

    // 2.迭代infos中的key/value
    const infos = {
      name: "why",
      age: 18,
      height: 1.88,

      [Symbol.iterator]: function() {
        // const keys = Object.keys(this)
        // const values = Object.values(this)
        const entries = Object.entries(this)
        let index = 0
        const iterator = {
          next: function() {
            if (index < entries.length) {
              return { done: false, value: entries[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    // 给infos创建一个迭代器, 迭代infos中的friends
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())


    // 可迭代对象必然具备下面的特点
    // const iterator = infos[Symbol.iterator]()
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())

    // 可迭对象可以进行for of操作
    for (const item of infos) {
      const [key, value] = item
      console.log(key, value)
    }

可迭代对象-原生可迭代对象

验证是否是可迭代对象的办法就是是否能调用[Symbol.iterator]()方法、并且可以使用for of来获取值。

 // 1.数组
    // const names = ["abc", "cba", "nba"]
    // for (const name of names) {
    //   console.log(name)
    // }
    // console.log(names[Symbol.iterator]())

    // 2.Set
    // const set = new Set(["abc", "cba", "nba"])
    // for (const item of set) {
    //   console.log(item)
    // }
    // const setIterator = set[Symbol.iterator]()
    // console.log(setIterator.next())
    // console.log(setIterator.next())
    // console.log(setIterator.next())
    // console.log(setIterator.next())

    // 3.arguments
    function foo() {
      for (const arg of arguments) {
        console.log(arg)
      }
    }

    foo(123, 321, 111, 222)

可迭代对象-可迭代对象场景

1

 // 1.用在特定的语法上
    const names = ["abc", "cba", "nba"]
    const info = {
      name: "why",
      age: 18,
      height: 1.88,
      [Symbol.iterator]: function() {
        const values = Object.values(this)
        let index = 0
        const iterator = {
          next: function() {
            if (index < values.length) {
              return { done: false, value: values[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    function foo(arg1, arg2, arg3) {
      console.log(arg1, arg2, arg3)
    }

    foo(...info)

    // 2.一些类的构造方法中, 也是传入的可迭代对象
    const set = new Set(["aaa", "bbb", "ccc"])
    const set2 = new Set("abc")
    console.log(set2)
    const set3 = new Set(info)
    console.log(set3)


    // 3.一些常用的方法
    const p1 = Promise.resolve("aaaa")
    const p2 = Promise.resolve("aaaa")
    const p3 = Promise.resolve("aaaa")
    const pSet = new Set()
    pSet.add(p1)
    pSet.add(p2)
    pSet.add(p3)
    Promise.all(pSet).then(res => {
      console.log("res:", res)
    })

    function bar() {
      // console.log(arguments)
      // 将arguments转成Array类型
      const arr = Array.from(arguments)
      console.log(arr)
    }

    bar(111, 222, 333)

可迭代对象-自定义类的迭代

把类的类属性迭代。

 class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      running() {}
      [Symbol.iterator]() {
        let index = 0
        const iterator = {
          next: () => {
            if (index < this.friends.length) {
              return { done: false, value: this.friends[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])
    const p2 = new Person("kobe", 30, 1.98, ["curry", "james", "aonier", "weide"])

    for (const item of p2) {
      console.log(item)
    }

可迭代对象-迭代器的中断(了解)

break、return、throw都可以中断迭代器

  class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      running() {}
      [Symbol.iterator]() {
        let index = 0
        const iterator = {
          next: () => {
            if (index < this.friends.length) {
              return { done: false, value: this.friends[index++] }
            } else {
              return { done: true }
            }
          },
          return: () => {
            console.log("监听到迭代器中断了")
            return { done: true }
          }
        }
        return iterator
      }
    }

    
    const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])

    for (const item of p1) {
      console.log(item)
      if (item === "kobe") {
        break
      }
    }

生成器-生成器函数基本使用

 /*
      生成器函数: 
        1.function后面会跟上符号: *
        2.代码的执行可以被yield控制
        3.生成器函数默认在执行时, 返回一个生成器对象
          * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
          * 当遇到yield时, 就会中断执行
    */

    // 1.定义了一个生成器函数
    function* foo() {
      console.log("1111")
      console.log("2222")
      yield
      console.log("3333")
      console.log("4444")
      yield
      console.log("5555")
      console.log("6666")
    }

    // 2.调用生成器函数, 返回一个 生成器对象
    const generator = foo()
    // 调用next方法
    generator.next()
    generator.next()
    generator.next()

生成器-生成器函数参数返回值

生成器配合迭代器的返回值可以返回相关的参数。

关于怎么给next传递参数,需要用到类似于这样子的写法,其中的aaaa是next()调用返回的参数。而name2是相当于形参使用。

传递第一次执行的参数时直接写在函数的形参里面。

// yield "aaaa"
const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
   // const names = ["abc", "cba", "nba"]
    // const iterator = names[Symbol.iterator]()
    // console.log(iterator.next())

    /*
      生成器函数: 
        1.function后面会跟上符号: *
        2.代码的执行可以被yield控制
        3.生成器函数默认在执行时, 返回一个生成器对象
          * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
          * 当遇到yield时, 就会中断执行
    */

    // 1.定义了一个生成器函数
    function* foo(name1) {
      console.log("执行内部代码:1111", name1)
      console.log("执行内部代码:2222", name1)
      // yield "aaaa"
      const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
      // yield "bbbb"
      const name3 = yield "bbbb"
      // return "bbbb"
      console.log("执行内部代码:5555", name3)
      console.log("执行内部代码:6666", name3)
      yield "cccc"
      return undefined
    }

    // 2.调用生成器函数, 返回一个 生成器对象
    const generator = foo("next1")
    // 调用next方法
    // console.log(generator.next()) // { done: false, value: "aaaa" }
    // console.log(generator.next()) // { done: false, value: "bbbb" }
    // console.log(generator.next()) //  { done: false, value: "cccc" }
    // console.log(generator.next()) // {done: true, value: undefined}

    // 3.在中间位置直接return, 结果
    // console.log(generator.next()) // { done: false, value: "aaaa" }
    // console.log(generator.next()) // { done: true, value: "bbbb" }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }

    // 4.给函数每次执行的时候, 传入参数
    console.log(generator.next())
    console.log(generator.next("next2"))
    console.log(generator.next("next3"))
    // console.log(generator.next())

生成器-生成器函数提前结束

通过return可以直接提前结束,但是我们需要的是可以控制的提前结束。这个时候直接使用return()来代替next()

 

 function* foo(name1) {
      console.log("执行内部代码:1111", name1)
      console.log("执行内部代码:2222", name1)
      const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
      const name3 = yield "bbbb"
      // return "bbbb"
      console.log("执行内部代码:5555", name3)
      console.log("执行内部代码:6666", name3)
      yield "cccc"

      console.log("最后一次执行")
      return undefined
    }

    const generator = foo("next1")

    // 1.generator.return提前结束函数
    // console.log(generator.next())
    // console.log(generator.return("next2"))
    // console.log("-------------------")
    // console.log(generator.next("next3"))
    // console.log(generator.next("next4"))

    // 2.generator.throw向函数抛出一个异常
    console.log(generator.next())
    console.log(generator.throw(new Error("next2 throw error")))
    console.log("-------------------")
    console.log(generator.next("next3"))
    console.log(generator.next("next4"))

生成器-生成器代替迭代器

生成器是特殊的迭代器,所以可以借助生成器来迭代课迭代对象。

 // 1.对之前的代码进行重构(用生成器函数)
    const names = ["abc", "cba", "nba"]
    const nums = [100, 22, 66, 88, 55]

    function* createArrayIterator(arr) {
      for (let i = 0; i < arr.length; i++) {
        yield arr[i]
      }
      // yield arr[0]
      // yield arr[1]
      // yield arr[2]
      // return undefined
    }

    // const namesIterator = createArrayIterator(names)
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())

    // const numsIterator = createArrayIterator(nums)
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())

    // 2.生成器函数, 可以生成某个范围的值
    // [3, 9)
    function* createRangeGenerator(start, end) {
      for (let i = start; i < end; i++) {
        yield i
      }
    }

    const rangeGen = createRangeGenerator(3, 9)
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())

生成器-生成器yield语法糖

yield* 可以直接迭代后面跟着的可迭代对象。

在类里面写生成器和平时不一样

 // 1.yield*替换之前的方案
    // const names = ["abc", "cba", "nba"]
    // const nums = [100, 22, 66, 88, 55]

    // function* createArrayIterator(arr) {
    //   yield* arr
    // }

    // const namesIterator = createArrayIterator(names)
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())

    // 2.yield替换类中的实现
    class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      *[Symbol.iterator]() {
        yield* this.friends
      }
    }

    const p = new Person("why", 18, 1.88, ["kobe", "james", "curry"])
    for (const item of p) {
      console.log(item)
    }

    const pIterator = p[Symbol.iterator]()
    console.log(pIterator.next())
    console.log(pIterator.next())
    console.log(pIterator.next())
    console.log(pIterator.next())

异步处理-异步请求代码结构(重要)

生成器函数可以解决一些回调地狱。async和await就是生成器的语法糖。

  // 封装请求的方法: url -> promise(result)
    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(url)
        }, 2000)
      })
    }

    // 1.发送一次网络请求
    // requestData("http://why").then(res => {
    //   console.log("res:", res)
    // })

    /*
      需求: 
        1.发送一次网络请求, 等到这次网络请求的结果
        2.发送第二次网络请求, 等待这次网络请求的结果
        3.发送第三次网络请求, 等待这次网络请求的结果
    */
    // 方式一: 层层嵌套(回调地狱 callback hell)
    // function getData() {
    //   // 1.第一次请求
    //   requestData("why").then(res1 => {
    //     console.log("第一次结果:", res1)

    //     // 2.第二次请求
    //     requestData(res1 + "kobe").then(res2 => {
    //       console.log("第二次结果:", res2)

    //       // 3.第三次请求
    //       requestData(res2 + "james").then(res3 => {
    //         console.log("第三次结果:", res3)
    //       })
    //     })
    //   })
    // }

    // 方式二: 使用Promise进行重构(解决回调地狱)
    // 链式调用
    // function getData() {
    //   requestData("why").then(res1 => {
    //     console.log("第一次结果:", res1)
    //     return requestData(res1 + "kobe")
    //   }).then(res2 => {
    //     console.log("第二次结果:", res2)
    //     return requestData(res2 + "james")
    //   }).then(res3 => {
    //     console.log("第三次结果:", res3)
    //   })
    // }

    // 方式三: 最终代码
    // function* getData() {
    //   const res1 = yield requestData("why")
    //   console.log("res1:", res1)

    //   const res2 = yield requestData(res1 + "kobe")
    //   console.log("res2:", res2)

    //   const res3 = yield requestData(res2 + "james")
    //   console.log("res3:", res3)
    // }

    // const generator = getData()
    // generator.next().value.then(res1 => {
    //   generator.next(res1).value.then(res2 => {
    //     generator.next(res2).value.then(res3 => {
    //       generator.next(res3)
    //     })
    //   })
    // })

    // 方式四: async/await的解决方案
    async function getData() {
      const res1 = await requestData("why")
      console.log("res1:", res1)

      const res2 = await requestData(res1 + "kobe")
      console.log("res2:", res2)

      const res3 = await requestData(res2 + "james")
      console.log("res3:", res3)
    }

    const generator = getData()

异步处理-生成器代码的优化(了解)

因为层数很多,我们想要自动调用

 // 封装请求的方法: url -> promise(result)
    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(url)
        }, 2000)
      })
    }

    // 生成器的处理方案
    function* getData() {
      const res1 = yield requestData("why")
      console.log("res1:", res1)

      const res2 = yield requestData(res1 + "kobe")
      console.log("res2:", res2)

      const res3 = yield requestData(res2 + "james")
      console.log("res3:", res3)

      const res4 = yield requestData(res3 + "curry")
      console.log("res4:", res4)

      const res5 = yield requestData(res4 + "tatumu")
      console.log("res5:", res5)
    }

    // const generator = getData()
    // generator.next().value.then(res1 => {
    //   generator.next(res1).value.then(res2 => {
    //     generator.next(res2).value.then(res3 => {
    //       generator.next(res3).value.then(res4 => {
    //         generator.next(res4)
    //       })
    //     })
    //   })
    // })

    // 自动化执行生成器函数(了解)
    function execGenFn(genFn) {
      // 1.获取对应函数的generator
      const generator = genFn()
      // 2.定义一个递归函数
      function exec(res) {
        // result -> { done: true/false, value: 值/undefined }
        const result = generator.next(res)
        if (result.done) return
        result.value.then(res => {
          exec(res)
        })
      }
      // 3.执行递归函数
      exec()
    }

    execGenFn(getData)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/754109.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

诚迈科技子公司智达诚远精耕智能驾驶,为商用落地注入创新力量

近期&#xff0c;工业和信息化部副部长辛国斌在新闻发布会上表示&#xff0c;将启动智能网联汽车准入和上路通行试点&#xff0c;组织开展城市级“车路云一体化”示范应用&#xff0c;将支持L3级及更高级别的自动驾驶功能商业化应用。根据工信部最新消息&#xff0c;《智能网联…

微聊测试报告

文章目录 微聊测试用例功能测试自动化测试注册页面登录页面会话窗口朋友圈界面 界面测试注册页面登录页面会话页面朋友圈页面 兼容性测试PCPad手机浏览器 性能测试安全测试密码保存是否安全SQL注入服务器错发 网络有网弱网断网 ​&#x1f451;作者主页&#xff1a;Java冰激凌 …

Pinia学习笔记 | 入门 - 映射辅助函数

文章目录 Pinia学习笔记简介Pinia是什么 代码分割机制案例1.挂载PiniaVue3Vue2&#xff1a;安装PiniaVuePlugin插件 2.定义store的两种方式options API 和 composition API使用options API模式定义使用composition API模式 2.业务组件对store的使用创建store实例解构访问Pinia容…

Vue学习笔记 之 Svg图标组件的实现步骤

1、安装依赖 首先需要安装svg-sprite-loader依赖&#xff0c;命令如下&#xff0c;这在在学习的过程中&#xff0c;就是因为没有下载该依赖&#xff0c;导致图标一直无法正常显示。 npm install svg-sprite-loader --save-dev --force2、配置svg图片处理规则 通过使用svg-spri…

【嵌入式Linux内核驱动】SPI子系统 | 硬件原理 | 应用编程 | 内核驱动 | 总体框架

1. 硬件原理 1.1 SPI通信协议 SPI&#xff08;Serial Peripheral Interface&#xff09;是由Motorola公司开发的一种通用数据总线 四根通信线&#xff1a;SCK&#xff08;Serial Clock&#xff09;、MOSI&#xff08;Master Output Slave Input&#xff09;、MISO&#xff08…

jmeter主要函数助手功用说明

jmeter中虽然有很多的插件&#xff0c;但是有些需要安装&#xff0c;有些具有一定的局限性。函数助手是一个快捷的工具库。下面记录一下函数助手中一些主要的函数的使用方法。 注&#xff1a;不内容中所有的实例均基于3.2记录 1、_BeanShell 表达式请求值后的值&#xff1a;可…

Hadoop之Hive安装

一、嵌入模式安装 1、下载Hive安装包 https://archive.apache.org/dist/hive/hive-1.2.1/ 2、上传至/root/export/software/ rz apache-hive-1.2.1-bin.tar.gz 3、解压 tar apache-hive-1.2.1-bin.tar.gz -C /root/export/servers/ cd /root/export/servers/apache-hive-1.2.…

openGauss学习笔记-09 openGauss 简单数据管理-创建数据库

文章目录 openGauss学习笔记-09 openGauss 简单数据管理-创建数据库9.1 语法格式9.2 参数说明9.3 示例 openGauss学习笔记-09 openGauss 简单数据管理-创建数据库 数据库安装完成后&#xff0c;默认生成名称为postgres的数据库。您需要自己创建一个新的数据库。 9.1 语法格式…

【Docker】Docker高级网络(NetWork)

【Docker】Docker高级网络(NetWork) 文章目录 【Docker】Docker高级网络(NetWork)1. 概述2. 网络2.1 网桥类型2.2 创建网络自定义桥2.3 查看所有网络2.4 查看特定网络的细节2.5 删除特定网络2.6 多个容器使用指定网络 参考文档&#xff1a;高级网络配置 Docker – 从入门到实践…

手机pdf怎么转换为图片?看看这几个转换方法

手机pdf怎么转换为图片&#xff1f;将手机图片转为PDF有很多好处。首先&#xff0c;PDF文件通常比图片文件更小&#xff0c;可以节省手机存储空间。其次&#xff0c;PDF文件可以更轻松地与他人共享&#xff0c;并且可以在不同设备和操作系统上打开。最后&#xff0c;将图片转换…

superheat | 超级简单的热图绘制解决方案!~(二)(聚类和注释图的添加~)

1写在前面 前面写了superheat的教程&#xff0c;今天写一下第二波&#xff0c;如何进行聚类以及添加注释图吧。&#x1f929; 分分钟提升你的heatmap的颜值哦&#xff01;~&#x1f970; 2用到的包 # devtools::install_github("rlbarter/superheat")library(superhe…

二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”

各位CSDN的uu们你们好呀&#xff0c;今天继续数据结构与算法专栏中的二叉树&#xff0c;下面&#xff0c;让我们进入二叉树的世界吧&#xff01;&#xff01;&#xff01; 二叉树&#xff08;上&#xff09;——“数据结构与算法”_认真学习的小雅兰.的博客-CSDN博客 二叉树链…

TypeScript 中对【泛型】的定义使用方式解读

目录 泛型函数多个泛型参数泛型约束泛型别名泛型接口泛型类 泛型&#xff08;Generics&#xff09;是指在定义函数、接口或类的时候&#xff0c;不预先指定具体的类型&#xff0c;而在使用的时候再指定类型的一种特性。使用泛型 可以复用类型并且让类型更加灵活 泛型实现类型参…

Pycharm安装 leetcode 插件

目录 本节演示Pycharm安装 leetcode 插件做算法题 打开设置&#xff1a; 点击插件&#xff1a; 搜索leetcode并安装&#xff1a; 点这里的 leetcode&#xff1a; 初次使用点这里&#xff1a; 这里输入账号和密码&#xff1a; 点击确定后还是点登录&#xff1a; 登…

【MySQL】SQL入门(一)

&#x1f697;MySQL学习起始站~ &#x1f6a9;本文已收录至专栏&#xff1a;数据库学习之旅 ❤️每章节附章节思维导图&#xff0c;文末附全文思维导图&#xff0c;感谢各位点赞收藏支出~ 一.引入 (1) SQL分类 SQL语句&#xff0c;根据其功能&#xff0c;主要分为四类&#x…

巧妙使用 CSS 渐变来实现波浪动画

目录 一、波浪的原理 二、曲面的绘制 三、波浪动画 四、文字波浪动画 五、总结一下 参考资料 之前看到coco[1]的这样一篇文章&#xff1a;纯 CSS 实现波浪效果&#xff01;[2]&#xff0c;非常巧妙&#xff0c;通过改变border-radius和不断旋转实现的波浪效果&#xff0c…

网络安全—全知识点解析(课程学习笔记)

概括来说&#xff0c;网络安全课程的主要内容包括&#xff1a; 安全基本知识 应用加密学 协议层安全 Windows安全&#xff08;攻击与防御&#xff09; Unix/Linux安全&#xff08;攻击与防御&#xff09; 防火墙技术 入侵监测系统 审计和日志分析 下面分别对每部分知识介绍相应…

Stable Diffusion - ControlNet 插件中扩展局部重绘 InpaintOnly + LaMa 算法与应用

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131643131 LaMa: https://github.com/advimman/lama Paper: Resolution-robust Large Mask Inpainting with Fourier Convolutions LaMa: Large…

哇~~真的是你呀!今天是在LINUX上简单部署LAMP平台。

目录 一、概述 二、PHP安装配置 三、安装 四、启动 五、书写测试页面 六、客户端访问 七、安装论坛 一、概述 LAMP组成&#xff1a; &#xff08;1&#xff09; Linux 其他组件的平台 &#xff08;2&#xff09;Apache提供web服务 &#xff08;3&#xff09;MySQL|Ma…

004-Triple协议底层原理分析

目录 底层分析Http 2.0 底层分析 Http 2.0 为了解决Http 1.0 和 1.1 头信息无法压缩有很多比如空格、换行等无用字符请求和相应不能并行处理&#xff1a;一个Socket连接如果接受到Request 就必须要等到服务返回Response了才能继续发送另一个Request 就更新了Http的协议到2.…