<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          true != true?面試官,你坑人?。?!

          共 6082字,需瀏覽 13分鐘

           ·

          2021-04-24 22:21

          閱讀本文大概需要 5 分鐘。

          本文總結(jié)一些初學(xué)者很容易犯錯的知識點(diǎn)。本文作者:橘中秘士。

          NULL

          SQL中 NULL 是一個特殊的值,其不滿足自反性,也就是NULL != NULL,如果用column = NULL試圖查詢值為NULL的數(shù)據(jù)注定悲劇。所以SQL單獨(dú)為其準(zhǔn)備了IS NULL語法。

          NaN

          IEEE754規(guī)定,有且僅有NaN不滿足自反性。假設(shè)NaN作為 key 存放了一個元素,那么該元素就像掉進(jìn)了黑洞,再也找不回來了。針對NaN也有自己的專用方法:IsNaN

          true != true

          這種場景需要刻意地去構(gòu)造,平時是遇不到的。舉一個例子:

          func main() {
           var j1 int8 = 1
           var b1 bool = *(*bool)(unsafe.Pointer(&j1))

           var j2 int8 = 2
           var b2 bool = *(*bool)(unsafe.Pointer(&j2))

           if b1 { // 編譯為TESTB
            println("b1 =", b1)
           }
           if b2 == true { // true是常量,編譯階段會自行處理,不會編譯為CMPB
            println("b2 = true")
           }
           if b1 == b2 { // 編譯為CMPB
            println("b1 = b2")
           } else {
            println("b1 != b2")
           }
          }

          b1b2都是通過unsafe “構(gòu)造”bool值,當(dāng)其與 if 或者其它需要bool類型的操作符搭配時,其表現(xiàn)出bool類型,當(dāng)其與==操作符或者其它(可以被bool類型和int8類型同時使用的)操作符搭配時,其表現(xiàn)出int8類型。

          根本原因在于 CPU 只認(rèn)指令,它的概念里沒有數(shù)據(jù)類型更不必說int8或者bool,所謂的類型是高級語言對于 CPU 指令的抽象[^0]。譬如TESTB指令的操作數(shù),編譯器把它稱為bool;CMPB對應(yīng)的操作數(shù),編譯器把它稱為int8或者uint8;CPU 指令有一組有符號移位和無符號移位,編譯器將其抽象為signedunsigned。

          反過來,編譯器把if還原成TESTB,將==還原成CMP,于是就出現(xiàn)了同樣的數(shù)值(同樣的內(nèi)存)在不同的指令下表現(xiàn)出了不一樣的行為。

          nil != nil

          這個場景初學(xué)者會經(jīng)常遇到,即使是大佬如果不注意也會被坑。

          但是如果理解了背后的原理,即使遇到也可以一笑帶過。

          package main

          type MyErr struct {
          }

          func (MyErr) Error() string {
           return "MyErr"
          }

          func main() {
           var e error = GetErr()
           println(e == nil)
          }

          func GetErr() *MyErr {
           return nil
          }
          • 出現(xiàn)這種“異?!爆F(xiàn)象一定存在函數(shù)調(diào)用,在單一函數(shù)內(nèi)部不存在“反?!爆F(xiàn)象。譬如在GetErr函數(shù)內(nèi)部,怎么造都不會出現(xiàn)nil != nil的怪胎。

          • 出現(xiàn)這種“異?!爆F(xiàn)象一定存在 interface type 引用 concrete type 的背景。譬如var e error改為var e *MyErr則不會出現(xiàn)nil != nil的怪胎。

          • interface type 引用 concrete type 時,隱含了convT2I[^1]。convT2I的主要作用在于用interface 的 typeconcrete 的 value合成了一個新值。

          • 如果是 concrete type 和 nil 比較,因?yàn)?type 是確定的,只要 value 對應(yīng)的內(nèi)存為 0 就可以認(rèn)定。

          • 如果是 interface type 和 nil 比較,需要 type 和 value 對應(yīng)的內(nèi)存同時為 0 才可認(rèn)定。由于允許只有 type 沒有 value[^2],不允許只有 value 沒有 type,所以可以簡化為 type 是否為指定。

          • 由于nil相對于編譯器來說相當(dāng)于字面常量,各個階段都存在不同程度的優(yōu)化。讓我們觀察一下interface typeinterface type之間的比較、interface typeconcrete type之間的比較,來感受一下編譯器是怎么處理 type 和 value 的。

          • interface typeinterface type之間的比較

          func walkcompareInterface(n *Node, init *Nodes) *Node {
            n.Right = cheapexpr(n.Right, init)
            n.Left = cheapexpr(n.Left, init)
            eqtab, eqdata := eqinterface(n.Left, n.Right)
            var cmp *Node
            if n.Op == OEQ { // x == y
              cmp = nod(OANDAND, eqtab, eqdata) // eqtab && eqdata
            } else { // x != y
              eqtab.Op = ONE
                  cmp = nod(OOROR, eqtab, nod(ONOT, eqdata, nil)) // !eqtab || !eqdata
            }
            return finishcompare(n, cmp, init)
          }
          • interface typeconcrete type
          if n.Left.Type.IsInterface() != n.Right.Type.IsInterface() { // 一個interface一個concrete
              l := cheapexpr(n.Left, init)
              r := cheapexpr(n.Right, init)
              // 如果需要,交換左右雙方,保證左側(cè)為interface右側(cè)為concrete。
              if n.Right.Type.IsInterface() {
                  l, r = r, l
              }

              // 如果是x == y,用&&連接;如果是x != y,用||連接。
              eq := n.Op
              andor := OOROR
              if eq == OEQ {
                  andor = OANDAND
              }
              // Check for types equal.
              // For empty interface, this is:
              //   l.tab == type(r)
              // For non-empty interface, this is:
              //   l.tab != nil && l.tab._type == type(r)
              var eqtype *Node
              tab := nod(OITAB, l, nil)
              rtyp := typename(r.Type)
              // 首先比較type
              if l.Type.IsEmptyInterface() {
                  tab.Type = types.NewPtr(types.Types[TUINT8])
                  tab.SetTypecheck(1)
                  eqtype = nod(eq, tab, rtyp)
              } else {
                  nonnil := nod(brcom(eq), nodnil(), tab)
                  match := nod(eq, itabType(tab), rtyp)
                  eqtype = nod(andor, nonnil, match)
              }
              // 其次比較value
              eqdata := nod(eq, ifaceData(n.Pos, l, r.Type), r)
              // 使用&&或者||連接兩個結(jié)果
              expr := nod(andor, eqtype, eqdata)
              n = finishcompare(n, expr, init)
              return n
          }

          [^0]: 譬如無符號長整型,C 稱之為 unsigned long int,Go 稱之為 uint64,Rust 稱之為 u64。
          [^1]: convT2I 是一類函數(shù)調(diào)用,譬如 convT2Inoptr,convT2E,convT2Enoptr,convT64,convT32,convT16 等等,包括被編譯器優(yōu)化掉的函數(shù)調(diào)用。
          [^2]: 譬如 var err *MyErr,指明了類型,但尚未賦值。




          往期推薦


          歡迎關(guān)注我

          都看到這里了,隨手點(diǎn)個贊支持下唄!


          瀏覽 41
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美成人精品在线视频 | 亚洲乱伦电影 | 丁香六月久久 | 婷婷五月伊人 | 苍空井久久久 |