Go資料結構:集合

分析和實現Go語言中的集合資料結構 集合是一組值的集合。您可以對這些值進行迭代,添加新值,刪除值並清除集合,獲取集合大小,以及檢查集合是否包含某個項目。集合中的值可能只會被存儲一次,不允許重複。 第一個實現 這是一個簡單的集合實現,尚未具備並發安全性,為了簡潔和易於理解,並沒有鎖定資源。稍後在本文中將添加鎖定。 請注意第二行,它允許我們通過生成此通用資料結構的特定實現來使用任何類型的集合。 set.go // 包set為Item類型創建ItemSet資料結構 package set import "github.com/cheekybits/genny/generic" // Item 集合的類型 type Item generic.Type // ItemSet 集合項目的集合 type ItemSet struct { items map[Item]bool } // Add 向集合中添加新元素。返回集合的指針。 func (s *ItemSet) Add(t Item) *ItemSet { if s.items == nil { s.items = make(map[Item]bool) } _, ok := s.items[t] if !ok { s.items[t] = true } return s } // Clear 從集合中刪除所有元素 func (s *ItemSet) Clear() { s.items = make(map[Item]bool) } // Delete 從集合中刪除項目並返回有無(項目) func (s *ItemSet) Delete(item Item) bool { _, ok := s....

Go語言中的運算子

迄今為止,在我們的代碼示例中已經使用了一些運算子,例如=,:=和<。 讓我們更深入地探討一下它們。 我們有賦值運算子=和:=,用於聲明和初始化變量: var a = 1 b := 1 我們有比較運算子==和!=,它們接受兩個參數並返回一個布爾值: var num = 1 num == 1 //true num != 1 //false 還有<,<=,>和>=: var num = 1 num > 1 //false num >= 1 //true num < 1 //false num <= 1 //true 我們有二元(需要兩個參數)算術運算子,如+,-,*,/,%。 1 + 1 //2 1 - 1 //0 1 * 2 //2 2 / 2 //1 2 % 2 //0 +也可以用於連接字符串: "a" + "b" //"ab" 我們有一元遞增、遞減運算子++和--:...

GPL授權協議

對於開發人員來說,您很可能會使用很多以GPL許可證發布的庫和軟件。 在本文中,我想對這個許可證進行一個高層次的概述,告訴您可以如何使用GPL軟件、不能使用GPL軟件,以及依賴於GPL軟件時您必須做些什麼。 GPL從歷史上來看,是開源軟件的核心。它最初由Richard Stallman於1989年創建,用於GNU計劃,這是一個基於UNIX操作系統的免費軟件版本,該操作系統當時是專有的。 自從GNU推出以來,對我們的行業產生了巨大的影響。我們稱之為“Linux”的伺服器和計算機實際上運行的是一個GNU/Linux系統。Linux是內核(即“核心”),核心周圍的一大部分是在GNU計劃的保護傘下生成的軟件,例如Bash和GNU C庫。GNU套件的完整列表非常長,其中包括您可能會使用的寶石,如wget、nano、gcc、gimp、emacs、gtk+等等。 注意:Android使用Linux作為其內核,但不包含GNU軟件,並在其上面包含專有軟件,這使其與桌面GNU/Linux發行版非常不同。此外,Android的開源部分採用的是Apache 2.0許可證,而不是GPL。 注意:本文介紹的是最新版本的GPL許可證v3。文章末尾將提供GPL v2的一些主要差異。 GPL v3軟件生產者的優點 作為以GPL v3許可證發布軟件的生產者,您不會對使用您的軟件產生的損害負責任。 如果您希望,您可以對軟件提供保修,但默認情況下您不會對此負責。 此外,作為以GPL許可證發布的軟件,不得重新發布以更寬鬆的許可證許可的軟件。 作為GPL軟件生產者,您必須提供以下內容: 在您分發的軟件包中包括GPL許可證的完整版本 包括您的版權 包括免責聲明 如果您分發軟件的可執行版本,您必須向所有請求的人提供軟件的源代碼。 此外(僅限GPL v3),如果軟件是消費者設備的一部分,您必須提供安裝說明,以允許任何人修改該軟件、構建二進制並重新安裝它。 如果您重新發布修改的GPL軟件版本,您還必須: 包括原始版本的版權 包括獲取原始版本的指南 包括對原始軟件所做的更改列表 GPL v3軟件用戶的優點 作為GPL v3軟件的用戶,您擁有很大的自由: 您可以將GPL軟件用於商業目的 您可以修改軟件並創建衍生作品 您可以在不需要請求許可或支付任何人的情況下,分發軟件及其任何衍生作品 此外,僅適用於GPL v3(不使用GPL v1或v2),您對使用的軟件的貢獻者擁有的任何專利都是安全的(他們給予您使用該軟件的內建權利,而不受他們擁有的任何專利的限制,他們不能起訴您使用該軟件)。 GPL v3軟件用戶的缺點 您無法更改收到的以GPL許可證發布的代碼的許可證。您可以對軟件進行修改,但不能將許可證更改為其他許可證。 一旦軟件被GPL授權,它將永遠附有該許可證。

GraphQL API vs REST API

主要介紹了REST與GraphQL之間的差異以及在什麼情況下使用其中之一。 由於REST是建立API的一種常用方法,比GraphQL更為廣泛使用,所以可以假設你對其相當熟悉,現在讓我們看看GraphQL和REST之間的差異。 REST是一種概念 REST是一種事實上的架構標準,但沒有具體的規範,有許多非官方定義。而GraphQL有一個規範草案,它是一個查詢語言,而不是一種架構,其周圍建立了一套明確的工具集(和一個蓬勃發展的生態系統)。 REST是建立在現有架構之上的,最常見的情況是使用HTTP。而GraphQL則正在構建自己的一套約定,這既可以是優點,也可能不是優點。因為REST可以通過HTTP層的緩存功能免費獲益。 單一端點 GraphQL只有一個端點,您將所有的查詢都發送到該端點。而REST則使用多個端點,並使用HTTP 動詞來區分讀取操作(GET)和寫入操作(POST,PUT,DELETE)。GraphQL不使用HTTP動詞來確定請求類型。 根據需求量身定制 在REST中,您通常無法選擇服務器返回的數據,除非服務器實現了使用稀疏字段集進行部分響應的功能,並且客戶端使用該功能。API維護者無法強制執行此類過濾。 除非您也控制API服務器並為每個不同的請求定制響應,否則API通常會返回比您所需的更多信息。 在GraphQL中,您明確要求您所需的信息,您不會“選擇退出”完整的默認響應,而需要選擇您想要的字段。 這有助於節省服務器的資源,因為您可能需要更少的處理,同時也節省了網絡流量,因為要傳輸的有效載荷更小。 一個很好的例子來形象地展示這一點是一個Pizza端點的示例(我是義大利人,一個披薩的例子很完美)。 如果你調用GET /pizza/margherita,你會得到一個馬若里披薩。 如果你調用GET /pizza/napoli,你會得到一個拿坡里披薩。 如果你有30個不同的口味,你將有30個端點(除非你把披薩名稱作為參數傳遞給GET /pizza,例如)。 但也許你想要一種特定的披薩,但卻不要一種你不喜歡的成分。向服務生提出這個要求很容易,但對於REST端點來說有點困難。 一個GraphQL端點將讓你調用/pizza,然後你可以要求特定的成分,來打造你想要的完美披薩。 GraphQL使得監測字段使用變得容易 在REST中通常無法確定客戶端是否需要某個字段,因此在進行重構或淘汰時,無法確定實際使用情況。 GraphQL使得追踪客戶端使用的字段成為可能。 訪問嵌套數據資源 GraphQL允許進行更少的網絡調用。 來看一個例子:您需要訪問一個人的朋友的名字。如果您的REST API公開了一個/person端點,該端點返回一個包含朋友ID列表的人物對象,通常可以先通過GET /person/1獲取人物信息,其中包含朋友的ID列表。 除非該人的朋友列表已經包含有朋友的名字,否則對於有100個朋友的情況,您需要對/person端點發起101個HTTP請求,這是一個巨大的時間成本,也是一個資源密集型操作。 而GraphQL只需要一個請求,該請求要求查詢該人物的朋友的名字。 類型 REST API基於無法提供類型控制的JSON。GraphQL具有一個類型系統。 哪一個更好? 全球各地的組織都在質疑他們的API技術選擇,他們正試圖找出從REST遷移到GraphQL是否適合他們的需求。 當您需要公開複雜的數據表示且客戶端可能只需要數據的子集,或者他們定期執行嵌套查詢以獲取所需的數據時,GraphQL非常適合。 和編程語言一樣,沒有絕對的贏家,一切都取決於您的需求。 同時,我還想說一點:您可以同時使用兩種方法。 您可以根據您的需求混合使用REST和GraphQL,有時這是最好的方法。

Heroku Redis 最大記憶體策略

Heroku提供了一個很棒的Redis插件,免費提供25MB的記憶體。 這個存儲量只需數千個項目即可輕鬆填滿,具體取決於您存儲的內容。 Heroku有一個名為maxmemory-policy的配置選項,它決定了當Redis數據庫內存填滿時系統的行為。 默認情況下,這個屬性被設置為noeviction,這意味著當嘗試存儲更多數據時,Redis會引發錯誤。 這樣做是為了讓您意識到正在發生的事情,一旦您發現可以更改此行為,那麼就是時候確定如何更改。 不同的行為由Redis自身提供,它們包括: noeviction:當達到內存限制並且客戶端嘗試執行可能導致使用更多內存的命令時,返回錯誤(大多數寫入命令,但DEL和其他一些命令除外)。 allkeys-lru:通過嘗試首先移除最近最少使用(LRU)的鍵來使空間為新增數據。 volatile-lru:通過嘗試首先移除最近最少使用(LRU)的鍵,但只在具有過期時間的鍵之間進行,以使空間為新增數據。 allkeys-random:隨機移除鍵以使空間為新增數據。 volatile-random:隨機移除鍵以使空間為新增數據,但只移除具有過期時間的鍵。 volatile-ttl:移除具有過期時間的鍵,並儘量首先移除TTL更短的鍵,以使空間為新增數據。 您需要找到最適合您需求的情況。一旦找到候選方案,您可以使用Heroku CLI應用更改,例如: heroku redis:maxmemory YOUR_REDIS_INSTANCE_NAME --policy volatile-lru

Homebrew 的實用指南

介紹流行的 Homebrew 套件管理器 Homebrew 是一個很好的套件管理器。原本是為 macOS 而開發的,現在也可以在 Linux 和 Windows Subsystem for Linux 上運行。 使用 Homebrew,你可以安裝幾乎任何你能想到的命令行應用程式,甚至是擁有完整圖形界面的應用程式。 如何安裝 Homebrew? 在 macOS 上,安裝 Homebrew 的指令如下: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 在 Linux/Windows 上,請參考官方網站的說明。 執行以上指令後,你就可以在終端機中使用 brew 命令了: 看到了嗎?我們有一個可以使用的子命令列表:brew install、brew upgrade、brew uninstall 等等。 安裝應用程式 使用 brew install 命令來安裝一個應用程式: brew install <包名> 例如,要安裝 mysql,執行以下命令: brew install mysql 這個命令有很多可用的選項,你可以查看它們: 你或許永遠不需要這些選項 - 我很少會使用除了預設的 brew install <package> 以外的其他選項。 有時候,某些套件(就像我在上面的示例中使用的 mysql 套件)會安裝成功,但在使用之前需要一些額外的步驟。 如果是這種情況,在安裝過程結束時,Homebrew 通常會提示給你。請確保你仔細閱讀 Homebrew 輸出到終端機的所有內容,以免日後出現問題。 套件安裝的位置在哪裡? 使用 Homebrew 安裝的套件都會被安裝到特定的資料夾中。...

how-to-detect-adblocker

如何使用JavaScript檢測是否正在使用廣告攔截程序 我使用的一種方法是,在我知道正在使用廣告攔截程序的情況下為網站添加自己的廣告。 對於像程序員這樣的專業使用者和技術人員來說,使用廣告攔截程序非常常見。 在我的網站上,我估計大約有20%到25%的訪問者使用某種形式的廣告攔截程序。 我對此沒有任何問題,儘管我支持通過廣告來維持博客運營,但我想做的一件事是,只有在啟用了廣告攔截程序時,才能推廣我自己的產品,這樣您才不會看到我使用的廣告網絡Carbon的廣告,而是一個我想要推廣的鏈接。 我不希望看到這種技術被用來顯示“停用廣告攔截程序!”這樣的消息,因為我發現當它被使用時,這很煩人。如果您這樣做,可以考慮促銷自己的產品,而不是廣告別人的產品。只是一個想法。 如果您現在啟用了廣告攔截程序,您可以在標題後面看到一個“贊助”詞語-那就是我想要推廣的產品-一個我目前正在構建的東西,我正在通過查看有多少人註冊等待列表來測試這個想法。 如果未啟用廣告攔截程序,該位置上會有一個廣告,所以我不想同時顯示太多廣告,以免對幫助經營這個博客的好人們產生不好的體驗。 這個JavaScript片段幫助我實現了這一點。 let adBlockEnabled = false const ad = document.createElement('div') ad.innerHTML = '&nbsp;' ad.className = 'adsbox' document.body.appendChild(ad) window.setTimeout(function() { if (ad.offsetHeight === 0) { adblockEnabled = true } ad.remove() console.log('是否阻擋了廣告? ', adblockEnabled) } }, 100) 請確保將它放在頁面底部以在DOM加載完成時運行,或者等待DOMContentLoaded事件。 一旦獲取到adblockEnabled的值,您就可以將自己的自定義廣告添加到頁面。 這是我用於執行此操作的腳本: if (adblockEnabled) { const link = document.createElement('a') link.setAttribute('href', 'https://flaviocopes.com') link.setAttribute('target', '_blank') const img = document.createElement('img') img.src = '/img/image.png' img.style.paddingBottom = '30px' img.style.margin = '0 auto' img....

how-to-find-duplicates-array-javascript

#JavaScript中如何找到陣列中的重複項目 如何在JavaScript陣列中找到並刪除重複項目 如果你想要刪除重複項目,有一個非常簡單的方法可以利用JavaScript提供的Set資料結構。只需一行程式碼即可完成: const yourArrayWithoutDuplicates = [...new Set(yourArray)] 如果你想要找出哪些項目是重複的,可以使用我們剛剛取得的"無重複陣列",並從原始陣列中刪除它包含的每一個項目: const yourArray = [1, 1, 2, 3, 4, 5, 5] const yourArrayWithoutDuplicates = [...new Set(yourArray)] let duplicates = [...yourArray] yourArrayWithoutDuplicates.forEach((item) => { const i = duplicates.indexOf(item) duplicates = duplicates .slice(0, i) .concat(duplicates.slice(i + 1, duplicates.length)) }) console.log(duplicates) //[ 1, 5 ] 另一個解決方案是將陣列排序,然後檢查"下一個項目"是否與當前項目相同,將其放入一個陣列中: const yourArray = [1, 1, 2, 3, 4, 5, 5] let duplicates = [] const tempArray = [...yourArray].sort() for (let i = 0; i < tempArray....

how-to-get-yesterday-date-javascript

#如何使用JavaScript獲取昨天的日期 你想要使用JavaScript獲取昨天的日期嗎? 那就先獲取當前時間的日期(今天),然後從它減去一天: const today = new Date() const yesterday = new Date(today) yesterday.setDate(yesterday.getDate() - 1) today.toDateString() yesterday.toDateString() 我們使用yesterday的setDate()方法,將當前日期減去一天作為參數。 即使今天是月份的第一天,JavaScript也會聰明地指向上個月的最後一天。

how-to-git-update-branch

#如何從另一個分支更新Git分支 假設有一個未與另一個分支同步的Git分支,該如何合併更改? 我正在使用一個與我在另一個分支上進行的更改不同步的Git分支進行工作。 因此,我需要導入這些更改。假設有一個未與另一個分支同步的Git分支,該如何合併更改? 您可以先切換到要更新的分支: git checkout my-branch 然後從要更新的分支合併: git merge another-branch 這將創建一個合併提交,其中包含兩個分支之間的所有差異-這是一個單獨的提交。 同時,您也可以參考我的Git指南。