主頁 >  其他 > 理解“閉包”

理解“閉包”

2022-03-13 06:29:33 其他

理解“閉包”

作者:哲思

時間:2021.9.5

郵箱:[email protected]

GitHub:zhe-si (哲思) (github.com)

前言

說起“閉包”,我的大腦里的第一反應不是在編程中常講的“閉包”,反而是大學離散數學課本中的“閉包”,為了明確二者的區別與聯系,并加強對“閉包的”本身的理解,我對“閉包”進行了一些研究,并撰寫此文,希望能給大家幫助,

離散數學——“閉包”

首先,簡單說明一下基本概念:

  • 集合:有限、無序、互異的元素組成的整體
  • 運算:n個集合映射到某一集合的映射程序
  • 關系:多個集合笛卡兒積的子集,如三元關系類似 <a, b, c>,可以想象為一個n維矩陣

接下來,給出“閉包”比較官方的定義:

【維基百科】

數學中,若對某個集合的成員進行一種運算,生成的仍然是這個集合的成員,則該集合被稱為在這個運算下閉合

  • 例如,實數在減法下閉合,但自然數不行(自然數 3 和 7 的減法 3 ? 7 的結果不是自然數),

當一個集合 S 在某個運算下不閉合的時候,我們通常可以找到包含 S 的最小的閉合集合,這個最小閉合集合被稱為 S 的(關于這個運算的)閉包

  • 例如,實數是減法運算下的閉合集合,即實數是減法運算下的閉包,而自然數則不是減法下的閉包,

簡單解釋,就是在給定的關系中,添加最少的元素,使其具有某種性質,則稱添加后的集合為該性質上關系的閉包,如:具有自反性,則為自反閉包,

再抽象一些:定義某個特定的、封閉的范圍,范圍內的元素滿足某些性質,就是該性質下的“閉包”

通過“閉包”,我們可以讓當前研究的關系利用構造閉包得到的性質進行簡化,反過來,也可以讓滿足某些性質的集合限定在某個確定且封閉的范圍內

函式式編程——“閉包”

概念理解

在js、python、kotlin等語言中常談的“閉包”,其實都是指的函式式編程中的“閉包”,也稱“詞法閉包”或“函式閉包”,

這個概念是在λ演算中被提出,并由Peter J. Landin在1964年引入術語——“閉包”(closure),定義中,“閉包”包括兩部分:環境部分、控制部分,

函式式編程的基礎就是λ演算,一種通過函式去描述世界的范式,重點是描述事物與事物間的關系,

介紹一種函式式語言:scheme(Lisp的一個方言)來描述lambda演算,

\[( define (f\ X)(Y)) \]

式中,定義了一個名為\(f\)的函式,引數是X,回傳值是Y

  • 引數:X可為任意個,寫作:\(x1\ x2\ ……\)

  • 回傳值:Y可為運算式(如:\((+\ x\ y)\),表示\(x + y\))或函式(如:\((lambda (x\ y)(+\ x\ y))\),表示一個接受引數\(x\)\(y\)并回傳\(x + y\)的函式)

現在,通過scheme定義一個\(x + y\)的函式(假設“+”運算已經定義):

\[(define\ (f\ x\ y)\ (+\ x\ y)) \]

可以通過該函式計算\(5 + 1\)

\[(f\ 5\ 1);\ Value:\ 6 \]

接下來,我們定義一個通用的函式,該函式可以回傳一個可以給某值\(x\)加固定值\(y\)的lambda函式:

\[(define\ (f\ y)\ (lambda\ (x)\ (+\ x\ y))) \]

該函式的引數是\(y\),回傳值是\((lambda\ (x)\ (+\ x\ y))\),我們將目光聚焦回傳值,可以看到,該函式接受一個引數\(x\),卻沒有\(y\)引數,\(y\)來自定義該回傳值函式的背景關系環境!也就是說,\(y\)由定義該函式時的背景關系環境決定,相對于定義的回傳值函式,\(y\)是自由的,來自環境,在不同環境下有不同表現,不被函式定義本身所限制\(x\)則被回傳值函式的定義宣告為該函式的引數,是系結在函式內的

我們繼續上面的例子,通過該函式得到一個可以給\(x\)加1的函式:

\[(f\ 1);\ Value:\ (lambda\ (x)\ (+\ x\ 1)) \]

那么,我們進一步實作給5加1的運算:

\[((f\ 1)\ 5);\ Value:\ 6 \]

這里總共發生了兩個程序:在\(f\)函式執行的區域環境下定義了一個函式、使用回傳的新定義的函式在其執行的區域環境下得到最終結果,

正常情況下,函式內的區域變數會在函式執行結束后釋放,但在該場景下,若\(y\)被釋放,則新定義的函式中的\(y\)就無法從環境中獲得了,所以,提出了一種機制,當函式在執行中,其內的某變數被其內定義的函式參考后,不會立刻釋放該變數,允許新定義的函式持有該變數的參考這就是在lambda演算中引入“閉包”的原因,這種機制產生的持有上層函式環境、新定義的函式,就叫“閉包”

現在,我們已經基本理解了“閉包”,最后給出它的一些經典定義:

【MDN】

閉包是將函式與其參考的周邊狀態系結在一起形成(封裝)的組合,

【犀牛書】

將函式物件和作用域相互關聯起來(一對變數的系結),函式體內部的變數都可以保存在函式作用域內,這種特性在計算機科學文獻中稱為閉包,

【維基百科】

在一些語言中,在函式中可以(嵌套)定義另一個函式時,如果內部的函式參考了外部的函式的變數,則可能產生閉包,閉包可以用來在一個函式與一組“私有”變數之間創建關聯關系,在給定函式被多次呼叫的程序中,這些私有變數能夠保持其持久性,

三個定義含義基本一致,簡單來說,就是\(閉包 = 函式 + 環境\),環境就是上面說到的作用域,

三個滿足閉包的條件:1. 訪問所在作用域;2. 函式嵌套;3. 在所在作用域外被呼叫,條件3是為了說明呼叫回傳新函式的程序中在記憶體里實際形成了閉包;而條件2不是絕對條件,從某種意義上,全域作用域也是一種環境;所以,滿足條件1即可稱為閉包,

畫龍點睛

到這里,偏向概念上的東西已經講完了,但還有一些重要的細節,在這里通過論斷的方式提出,

  1. 函式式編程,允許運行時定義函式

    在上面,我們一直沒有關注一個事情——我們不是靜態的在編譯前定義的函式,而是在運行時動態定義的,這是函式式編程的關鍵之一,也是閉包形成的基礎,

    在上面lambda演算的例子中,我們每次在某個環境下動態定義新的函式,并將環境保存,進而形成了閉包,

  2. 函式的每次呼叫都會產生一個新的環境

    環境產生的時機是每次呼叫,其區域環境在呼叫后產生并作為運行時新動態定義的函式的環境,

    這里強調一個點——“每次呼叫”,也就是說,如果只有一次函式呼叫,在其內定義多個新函式,每個新函式共享環境,

    這里是一個很容易出錯的地方,來個例題:利用閉包,修改下面的代碼,讓回圈輸出的結果依次為1, 2, 3, 4, 5,

    該例中,我們期望每一個timer參考的i的取值作為一個獨立的環境,這樣timer閉包就可以輸出不同的數字,

    而在下面給定的源代碼中,定義的多個新函式系結的是同一個環境(最外層函式的 i 區域變數),導致每個輸出都為i的最終值6,

    for (var i = 1; i <= 5; i++) {
      setTimeout(function timer() {
        console.log(i);
      }, i * 1000);
    }
    

    我們為每一個 i 的取值添加了一個函式的呼叫,對應產生了一個獨立的環境,每一個新定義的timer都使用獨立環境的 ii 變數,實作了我們的目標效果,

    for (var i = 1; i <= 5; i++) {
      (function () {
        var ii = i;
        setTimeout(function timer() {
          console.log(ii);
        }, i * 1000);
      })()
    }
    
  3. 呼叫定義新函式的函式才會產生新的閉包

    閉包的產生對應一個新的函式被定義出來,與閉包函式本身被呼叫無關,

    這里也有一個例子:

    var fn = null;
    function foo() {
      var a = 2;
      function innnerFoo() {
        console.log(c); // 在這里,試圖訪問函式bar中的c變數,會拋出錯誤
        console.log(a);
      }
      fn = innnerFoo; // 將 innnerFoo的參考,賦值給全域變數中的fn
    }
    
    function bar() {
      var c = 100;
      fn(); // 此處的保留的innerFoo的參考
    }
    
    foo();
    bar();
    

    本例中,試圖在bar函式中呼叫某閉包函式訪問bar內的區域變數,期望讓閉包函式本身的呼叫影響閉包的產生,顯然是錯誤的,

    還是那句話,只有呼叫定義新函式的函式(或者像本例將新定義的函式通過保存在一個變數而不是作為回傳值回傳)的時候產生的環境才可以被閉包函式參考并產生新的閉包,

  4. 一般,閉包系結的環境只包含用到的部分

    也就是說,一般不會不考慮用不用都把環境完整保存(這樣沒有參考所在外部作用域的非閉包函式豈不也要像閉包一樣將環境保存?),而是用了哪個變數就保存那個變數,

    舉個例子:

    我們定義一個兩層嵌套的閉包函式c,來探究部分系結的問題,

    python版本

    def a():
        a1 = 4
        a2 = 5
    
        def b():
            b1 = 7
            b2 = 8
    
            def c():
                c1 = 12
                c2 = 13
                return c1 + b1
                # return c1 + a1
            return c
        return b
    

    js版本

    function a() {
        var a1 = 1;
        var a2 = 2;
        return function b() {
            var b1 = 11;
            var b2 = 12;
            return function c() {
                var c1 = 101;
                var c2 = 102;
                return c1 + b1; 
                // return c1 + a1;
            }
        }
    }
    

    我們只看最內層的閉包函式c,如果參考b1,則回傳的函式只包含環境中的b1;如果參考a1,則回傳的函式只包含環境中的a1,參考b2、a2同理,大家可以親手嘗試一下,

    結果用js進行展示,如下圖:

    閉包嵌套js結果

    閉包嵌套js結果2

實作剖析

以js為例,介紹一下閉包基本的實作方式,

在js中,變數分為兩種,區域和全域,并通過一個作用域鏈存盤在堆中,

當查找變數時,會從作用域鏈末端(一般,末端即是當前作用域下的存盤節點)向上游進行查找,直到找到目標變數,這也是函式可以參考外部作用域的變數的原因,

當函式執行結束釋放時,一般會將其對應的區域存盤空間釋放,也就是由gc垃圾回識訓制對無有效參考或不可達的物件進行釋放,但由于引入了閉包,允許作用域內定義的新函式持有當前作用域的變數的參考(注意,不是拷貝),再加上新函式被回傳后保存,導致變數被閉包函式持有有效參考而無法被垃圾回識訓制釋放,這就是閉包實作的基本原理,

給一個簡單的例子,如下圖,在全域呼叫foo函式,foo函式定義并回傳一個新的innerFoo閉包函式保存在全域,回傳的閉包函式持有foo函式呼叫中的區域變數arguments,在foo執行結束后,會釋放除新定義的閉包函式innerFoo以及對應的環境arguments變數之外的其他區域變數(a變數),

閉包原理圖

同時,由于保留下來的環境只有對應的閉包函式持有參考,所以也只能通過閉包函式進行訪問,也就產生了一個訪問的作用域,該特性可以避免使用全域變數,防止全域變數對命名空間等的污染,

這樣的實作方式,讓區域變數可以不跟隨定義它的函式的結束而釋放,讓外部訪問函式內的區域變數成為可能,但同時,更復雜的參考持有機制也容易造成記憶體泄漏,

類似技術對照

閉包技術是函式式編程解決定義函式依靠的資料與函式的系結問題,同時提供變數私有化、區域化的效果,這與面向物件封裝資料與對應方法的思路十分相似,(如果不熟悉面向物件,可以參考文章:從面向物件解讀設計思想,包含了對面向物件從淺入深的講解)

常見的兩個相似技術是函式物件和內部類:

  • 函式物件:

    c++通過自定義類多載"()"運算子可以實作一種類似函式的呼叫方式,同時可以自由定義和配置不同物件(修改其內屬性的值)來實作"()"運算子呼叫的不同效果,類似閉包系結不同環境,

    python也可以通過定義“_call_”魔術方法實作類似效果,

  • 內部類:

    java支持在函式中定義一個內部類,在內部類中可以參考外部函式的區域變數以及外部類的屬性,

    這個特性,也被java用來支持函式式編程的實作,如java中的lambda運算式,

思想拓展

沒有證據可以證明該術語與數學中的“閉包”的關系,但我認為這里的“閉包”是數學中“閉包”概念上的一種引申,

數學中某性質的閉包指某個特定的、封閉的范圍,范圍內的元素都滿足該性質,

在函式式編程的閉包中,閉包函式系結的環境本身即可看成一種特定、封閉的范圍,而函式就是該環境下滿足的性質,

雖然沒有將二者統一的必要,但確實可以從抽象形式上看出二者的一些相似性,同時,這些相似性也有益于我們去更好的理解與運用“閉包”,

【拓展】資料庫——“閉包”

在關系型資料庫中,定義了屬性集和FD集(函式依賴,某個屬性決定另一個屬性時,稱另一屬性依賴于該屬性),則某屬性子集的“閉包”指該子集所有屬性與基于該子集通過函式依賴可以推匯出的所有屬性的集合,

\[子集A的閉包 = 子集A \ ∪ \ 子集A通過FD集推匯出的所有屬性集合 \]

舉個例子:

屬性集:\(A\ B\ C\ D\)

FD集:\(\{ A \rightarrow B, B \rightarrow C, D \rightarrow B \}\)

記子集T的閉包為\(T^+\),則:

  • \(A^+ = A B C\)

    解釋:A可以推匯出B,B推匯出C,加起來為ABC

  • \((AD)^+ = ABCD\)

    解釋:A可以推匯出B,B推匯出C,D推匯出B,加起來為ABCD

  • \((BD)^+ = BCD\)

    解釋:B可以推匯出C,D可以推匯出B,加起來為BCD

從上面的概念和例子中可以明顯看出,在資料庫中“閉包”的概念是離散數學中“閉包”概念的推廣,這里的運算就是FD集,滿足FD集這樣的性質的最小集合就是某子集在該性質下的閉包,

后記

關于“閉包”這個單詞的含義還有很多,本文只是介紹了數學和計算機領域比較重要的概念與理解,但在了解了諸多領域對于該詞的描述后,發現萬變不離其宗,都是在研究一個滿足某些性質的封倍訓境(范圍),可能,這本身就是認識論和方法論的一個重要內容——讓我們在一個確定的范圍內,去探究事物的本質,

本文來自博客園,作者:_哲思,轉載請注明原文鏈接:https://www.cnblogs.com/zhe-si/p/15999113.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/441943.html

標籤:其他

上一篇:Java案例——ArrayList存盤學生物件并遍歷

下一篇:為什么這個錯誤“TypeError:最多執行2個引數,得到3個”?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more