国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 后端開發(fā) Golang 極簡密碼管理器桌面應(yīng)用程序:進(jìn)軍 Golang 的 Wails 框架(第 2 部分)

極簡密碼管理器桌面應(yīng)用程序:進(jìn)軍 Golang 的 Wails 框架(第 2 部分)

Dec 30, 2024 am 09:50 AM

各位程序員,大家好!在這個(gè)簡短系列的第一部分中,我們看到了桌面應(yīng)用程序的創(chuàng)建和操作,用于存儲(chǔ)和加密使用 Wails 框架創(chuàng)建的密碼。我們還描述了 Go 后端以及如何將其綁定到前端。

在這一部分中,我們將處理用戶界面。正如我們在那篇文章中所述,Wails 允許我們使用任何我們喜歡的 Web 框架,甚至 Vanilla JS,來構(gòu)建我們的 GUI。正如我所說,Wails 的創(chuàng)作者似乎偏愛 Svelte,因?yàn)樗麄兛偸菍⑵渥鳛槭走x。當(dāng)我們要求使用 Svelte Typescript (wails init -n myproject -t svelte-ts) 創(chuàng)建項(xiàng)目時(shí),Wails CLI(當(dāng)前版本)會(huì)使用 Svelte3 生成腳手架。正如我已經(jīng)告訴過您的,如果您更喜歡使用 Svelte5(及其新功能),我有一個(gè) bash 腳本可以自動(dòng)創(chuàng)建它(無論如何,您必須安裝 Wails CLI)。此外,它還添加了 Taildwindcss Daisyui,這在我看來是界面設(shè)計(jì)的完美組合。

事實(shí)是,我首先使用 Vanilla JsVue,然后使用 React,甚至使用那個(gè)對(duì)于許多人來說是React 的奇怪庫。 ??>HTMX(我不得不說我喜歡??)。但是Svelte

讓你從一開始就愛上它,我不得不說,我是在嘗試Wails時(shí)第一次使用它的(我保證會(huì)繼續(xù)使用它......)。但是,盡管 Web 框架很舒服,但我們必須提醒后端開發(fā)人員,前端并不那么容易??。?p>

但是讓我們進(jìn)入正題吧。

I - 前端結(jié)構(gòu)概覽


如果您使用過任何 Web 框架,您很快就會(huì)認(rèn)識(shí)到 Wails CLI 在底層使用了 ViteJ:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

如果您使用過 Vite 生成的任何 Web 框架,您不會(huì)對(duì)其配置文件感到驚訝。這里我使用 Svelte5 (加上 Taildwindcss Daisyui 的配置),這就是生成我自己的 bash 腳本的原因,正如我已經(jīng)告訴過你的。我們還使用了TypeScript

,這樣會(huì)方便前端的開發(fā),所以你也可以看到它的配置。

但是這個(gè)解釋中最重要的是wailsjs文件夾的內(nèi)容。這就是Wails 所做的編譯發(fā)揮其魔力的地方。 go 子文件夾是存儲(chǔ)必須與前端交互的后端部分的“翻譯”為 Js/Ts
的方法的位置。例如,在 main/App.js(或其 TypeScript 版本 main/App.d.ts)中,有 App 結(jié)構(gòu)的所有導(dǎo)出(公共)方法:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

他們都返回一個(gè)承諾。如果 Promise“包裝”了一些用作返回類型的 Go 結(jié)構(gòu),或者相應(yīng)的函數(shù)采用參數(shù)類型,則會(huì)有一個(gè)模塊(models.ts,在本例中為類型,因?yàn)槲覀兪褂?TypeScript),其中包含與 Go 對(duì)應(yīng)的類命名空間中的結(jié)構(gòu)及其構(gòu)造函數(shù)。

此外,runtime 子文件夾包含 Go 運(yùn)行時(shí)包中的所有方法,這些方法允許我們分別操作窗口以及從后端偵聽或發(fā)出的事件。

src 文件夾包含將由 Vite 編譯的文件,并將它們保存在“frontend/dist”中(并嵌入到最終的可執(zhí)行文件中),就像在任何 Web 應(yīng)用程序中一樣。請(qǐng)注意,由于我們使用 Tailwindcss,因此 style.css 包含基本的 Tailwind 配置以及我們需要使用的任何 CSS 類。此外,作為界面使用網(wǎng)絡(luò)技術(shù)的一個(gè)優(yōu)勢,我們可以輕松地使用一種或多種字體(文件夾資產(chǎn)/字體)或交換它們。

為了完成這個(gè)概述,請(qǐng)注意,當(dāng)我們在開發(fā)模式(wails dev)下編譯時(shí),除了允許我們熱重載之外,我們不僅可以觀察所做的更改(無論是在后端還是在前端)應(yīng)用程序窗口本身,而且還通過地址 http://localhost:34115 在 Web 瀏覽器中,因?yàn)?Web 服務(wù)器已啟動(dòng)。這允許您使用您最喜歡的瀏覽器開發(fā)擴(kuò)展。雖然必須說Wails本人為我們提供了一些非常有用的開發(fā)工具,但是當(dāng)我們右鍵單擊應(yīng)用程序窗口(僅在開發(fā)模式下)并選擇“Inspect Element”時(shí):

A minimalist password manager desktop app: a foray into Golang

II - 現(xiàn)在……深入研究 HTML、CSS 和 JavaScript?


// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

如你所見,我已經(jīng)向 Svelte 添加了 4 個(gè) JavaScript 包(除了已經(jīng)提到的 Tailwindcss Daisyui):

  • svelte-copy,可以更輕松地將用戶名和密碼復(fù)制到剪貼板。
  • svelte-i18n,用于 i18n 處理,即允許用戶更改應(yīng)用程序的語言。
  • svelte-spa-router,Svelte 的一個(gè)小型路由庫,它可以更輕松地更改應(yīng)用程序窗口中的視圖,因?yàn)樵谶@種情況下,使用由SvelteKit。
  • sweetalert2,基本上用它來輕松快速地創(chuàng)建模態(tài)框/對(duì)話框。

每個(gè) SPA 的入口點(diǎn)都是 main.js(或 main.ts)文件,所以讓我們從它開始:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

我突出顯示了添加到由 Wails CLI 生成的框架中的內(nèi)容。 svelte-i18n 庫要求在 main.js/ts 文件中注冊包含翻譯的 JSON 文件,同時(shí)設(shè)置 fallback/initial 語言(盡管我們'你會(huì)看到,稍后將根據(jù)用戶選擇的偏好進(jìn)行操作)。包含翻譯的 JSON 文件的格式為:

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

我發(fā)現(xiàn)這個(gè)庫的系統(tǒng)對(duì)于促進(jìn) Svelte 應(yīng)用程序的翻譯非常簡單和方便(您可以查閱其文檔以了解更多詳細(xì)信息):

/* package.json */
...
},
  "dependencies": {
    "svelte-copy": "^2.0.0",
    "svelte-i18n": "^4.0.1",
    "svelte-spa-router": "^4.0.1",
    "sweetalert2": "^11.14.5"
  }
...

您還可以使用像這樣的網(wǎng)站,它將幫助您將 JSON 文件翻譯成不同的語言。然而,問題是,當(dāng)您使用 $format 填充 .svelte 文件時(shí),您必須手動(dòng)跟蹤它們,這是乏味且容易出錯(cuò)的。我不知道有什么方法可以自動(dòng)完成這項(xiàng)任務(wù),如果有人知道,我會(huì)很感興趣,如果你能讓我知道?...否則,我必須想出某種腳本來完成這項(xiàng)工作。

與任何 Svelte 應(yīng)用程序一樣,構(gòu)建界面的下一步是 App.svelte 文件:

/* main.ts */

import { mount } from 'svelte'
import './style.css'
import App from './App.svelte'
import { addMessages, init } from "svelte-i18n"; // ? ?
import en from './locales/en.json'; // ? ?
import es from './locales/es.json'; // ? ?

addMessages('en', en); // ? ?
addMessages('es', es); // ? ?

init({
  fallbackLocale: 'en', // ? ?
  initialLocale: 'en', // ? ?
});

const app = mount(App, {
  target: document.getElementById('app')!,
})

export default app

這里我們使用 GetMasterPassword,它是編譯應(yīng)用程序時(shí)自動(dòng)生成的 綁定,并被聲明為 struct App 的公共方法(請(qǐng)參閱本系列的第一部分)。該函數(shù)查詢數(shù)據(jù)庫,如果其中注冊了主密碼,它會(huì)認(rèn)為用戶已經(jīng)注冊(它返回一個(gè)包含布爾值的承諾),要求他輸入所述密碼以允許他訪問其余內(nèi)容的意見。如果數(shù)據(jù)庫中沒有主密碼,則該用戶被視為“新”,要求他生成自己的密碼以首次進(jìn)入應(yīng)用程序。

最后,在安裝 Login.svelte 組件時(shí),我們做了一些對(duì)應(yīng)用程序的其余部分很重要的事情。盡管 svelte-i18n 庫強(qiáng)制我們聲明初始語言代碼,但正如我們已經(jīng)看到的,在安裝 Login.svelte 時(shí),我們要求數(shù)據(jù)庫(使用 GetLanguage 綁定)檢查是否保存了語言代碼。如果數(shù)據(jù)庫返回空字符串,即沒有配置為用戶首選項(xiàng)的語言,svelte-i18n 將使用配置為initialLocale 的值。如果配置了一種語言,則將設(shè)置該語言 (locale.set(result);) 并發(fā)出“change_titles”事件,標(biāo)題欄和應(yīng)用程序本機(jī)對(duì)話框的翻譯標(biāo)題將傳遞到該事件供后端處理:

/* frontend/src/locales/en.json */

{
    "language": "Language",
    "app_title": "Nu-i uita ? minimalist password store",
    "select_directory": "Select the directory where to save the data export",
    "select_file": "Select the backup file to import",
    "master_password": "Master Password ?",
    "generate": "Generate",
    "insert": "Insert",
    "login": "Login",
    ...
}


/* frontend/src/locales/es.json */

{
    "language": "Idioma",
    "app_title": "Nu-i uita ? almacén de contrase?as minimalista",
    "select_directory": "Selecciona el directorio donde guardar los datos exportados",
    "select_file": "Selecciona el archivo de respaldo que deseas importar",
    "master_password": "Contrase?a Maestra ?",
    "generate": "Generar",
    "insert": "Insertar",
    "login": "Inciar sesión",
    ...
}

以下是處理登錄的邏輯:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

簡單地說:newPassword,綁定到獲取用戶輸入內(nèi)容的輸入的狀態(tài),首先由 onLogin 檢查它是否至少有 6 個(gè)字符,并且它們都是 ASCII 字符,即,通過這個(gè)小函數(shù) const isAscii = (str: string): boolean => 它們只有 1 個(gè)字節(jié)長(請(qǐng)參閱本系列第一部分中的原因)。 /^[x00-x7F] $/.test(str);.如果檢查失敗,該函數(shù)將返回并向用戶顯示警告 toast。之后,如果數(shù)據(jù)庫中沒有保存主密碼(isLogin = false),則 SaveMasterPassword 函數(shù)將保存用戶輸入的任何內(nèi)容(Wails 生成的綁定);如果 Promise 成功解析(返回 uuid 字符串作為數(shù)據(jù)庫中存儲(chǔ)的記錄的 Id),用戶將被 svelte-spa-router 帶到主頁視圖庫的推送方法。相反,如果密碼通過了長度檢查,且不存在 非 ASCII 字符,并且數(shù)據(jù)庫中存在主密碼 (isLogin = true),則 CheckMasterPassword 函數(shù)將根據(jù)存儲(chǔ)的密碼驗(yàn)證其身份,或者將用戶帶到主視圖(promise 為 true 解決)或顯示 toast 表明輸入的密碼不正確。

應(yīng)用程序的中心視圖,同時(shí)也是最復(fù)雜的視圖是主頁視圖。它的 HTML 實(shí)際上分為 3 個(gè)組件:一個(gè)帶有搜索輸入的頂部按鈕欄(TopActions 組件)、一個(gè)底部按鈕欄(BottomActions 組件)以及一個(gè)中心區(qū)域,其中使用以下命令顯示已保存密碼條目的總數(shù)或這些條目的列表:可滾動(dòng)窗口(EntriesList 組件):

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

也就是說,它使搜索狀態(tài)(searchTerms)成為一個(gè)空字符串,這樣如果有任何搜索詞,它就會(huì)被重置,從而顯示整個(gè)列表。另一方面,它切換 showList 狀態(tài)(props TopActions 中的 isEntriesList),以便父組件顯示或隱藏列表。

正如我們在上圖中看到的,兩個(gè)子組件與父組件的 searchTerms 狀態(tài)共享相同的 props。 TopActions 組件捕獲用戶的輸入,并將其作為狀態(tài)傳遞給父組件 Home,而父組件 Home 又將其作為 props 傳遞給其子組件 EntriesList。

顯示完整列表或按用戶輸入的搜索詞過濾的列表的主要邏輯按預(yù)期由 EntriesList 組件執(zhí)行:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

正如我們所說,收到 2 個(gè) props(listCounter 和 search)并維護(hù)一個(gè)狀態(tài)(讓條目:models.PasswordEntry[] = $state([]);)。當(dāng)根據(jù)用戶的請(qǐng)求安裝該組件時(shí),后端會(huì)被要求提供已保存密碼條目的完整列表。如果沒有搜索詞,則將其存儲(chǔ)在狀態(tài)中;如果有,則對(duì)獲得的數(shù)組進(jìn)行簡單過濾,并將其保存在狀態(tài):

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

在顯示的列表中,用戶可以執(zhí)行 2 個(gè)操作。第一個(gè)是顯示條目的詳細(xì)信息,當(dāng)他點(diǎn)擊相應(yīng)的按鈕時(shí)執(zhí)行:onclick={() =>推送(`/details/${entry.Id}`)}?;旧?,我們調(diào)用路由庫的 Push 方法將用戶帶到詳細(xì)信息視圖,但傳遞與相關(guān)項(xiàng)目相對(duì)應(yīng)的 Id 參數(shù)。

用戶可以執(zhí)行的另一個(gè)操作是從列表中刪除項(xiàng)目。如果他單擊相應(yīng)的按鈕,將顯示一個(gè)確認(rèn)彈出窗口,調(diào)用 showAlert 函數(shù)。該函數(shù)依次調(diào)用 showWarning,它實(shí)際上是 sweetalert2 庫的抽象層(調(diào)用 sweetalert2 庫的所有函數(shù)都在 frontend/src/lib/popups/popups.ts 中)。如果用戶確認(rèn)刪除操作,則調(diào)用DeleteEntry綁定(將其從數(shù)據(jù)庫中刪除),反過來,如果它返回的promise得到解析,則調(diào)用deleteItem(將其從存儲(chǔ)在條目狀態(tài)的數(shù)組中刪除) :

/* package.json */
...
},
  "dependencies": {
    "svelte-copy": "^2.0.0",
    "svelte-i18n": "^4.0.1",
    "svelte-spa-router": "^4.0.1",
    "sweetalert2": "^11.14.5"
  }
...

主頁視圖的另一個(gè)組件(BottomActions)要簡單得多:它不接收 props 并且僅限于將用戶重定向到各種視圖(Settings、About 或 AddPassword)。

AddPassword 和 EditPassword 視圖的邏輯非常相似,也與 Login 視圖類似。兩者都不允許用戶在文本輸入的開頭和結(jié)尾輸入空格,并遵循與登錄視圖相同的策略,要求密碼長度至少為 6 個(gè) ASCII 字符?;旧希鼈兊呐c眾不同之處在于它們調(diào)用與需要執(zhí)行的操作相關(guān)的由 Wails 生成的鏈接:

/* main.ts */

import { mount } from 'svelte'
import './style.css'
import App from './App.svelte'
import { addMessages, init } from "svelte-i18n"; // ? ?
import en from './locales/en.json'; // ? ?
import es from './locales/es.json'; // ? ?

addMessages('en', en); // ? ?
addMessages('es', es); // ? ?

init({
  fallbackLocale: 'en', // ? ?
  initialLocale: 'en', // ? ?
});

const app = mount(App, {
  target: document.getElementById('app')!,
})

export default app

另一個(gè)有點(diǎn)復(fù)雜的視圖是“設(shè)置”。它有一個(gè)語言組件,它從其父組件(設(shè)置)接收 props languageName:

/* frontend/src/locales/en.json */

{
    "language": "Language",
    "app_title": "Nu-i uita ? minimalist password store",
    "select_directory": "Select the directory where to save the data export",
    "select_file": "Select the backup file to import",
    "master_password": "Master Password ?",
    "generate": "Generate",
    "insert": "Insert",
    "login": "Login",
    ...
}


/* frontend/src/locales/es.json */

{
    "language": "Idioma",
    "app_title": "Nu-i uita ? almacén de contrase?as minimalista",
    "select_directory": "Selecciona el directorio donde guardar los datos exportados",
    "select_file": "Selecciona el archivo de respaldo que deseas importar",
    "master_password": "Contrase?a Maestra ?",
    "generate": "Generar",
    "insert": "Insertar",
    "login": "Inciar sesión",
    ...
}

此組件的 HTML 是一個(gè)處理用戶語言選擇的 select。在其 onchange 事件中,它接收一個(gè)函數(shù) (handleChange),該函數(shù)執(zhí)行 3 件事:

  • 使用 svelte-i18n 庫設(shè)置前端語言
  • 發(fā)出一個(gè)事件(“change_titles”),以便Wails運(yùn)行時(shí)更改應(yīng)用程序標(biāo)題欄的標(biāo)題以及相關(guān)的選擇目錄選擇文件對(duì)話框的標(biāo)題到上一個(gè)操作
  • 將用戶選擇的語言保存在數(shù)據(jù)庫中,以便下次啟動(dòng)應(yīng)用程序時(shí),它將打開配置為該語言的。

返回“設(shè)置”視圖,其整個(gè)操作由一系列發(fā)送到后端或從后端接收的事件控制。最簡單的是退出按鈕:當(dāng)用戶單擊它時(shí),會(huì)在后端觸發(fā)并偵聽退出事件,然后應(yīng)用程序關(guān)閉(onclick={() => EventsEmit("quit")})。 提示 通知用戶 Escape 鍵(快捷鍵)執(zhí)行相同的操作,正如我們已經(jīng)解釋過的。

重置按鈕調(diào)用顯示彈出窗口的函數(shù):

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

如果用戶接受該操作,則會(huì)調(diào)用 Drop 綁定,這會(huì)清除數(shù)據(jù)庫中的所有 collections,如果它返回的 Promise 得到解析,則會(huì)將用戶發(fā)送到 Login 視圖,顯示指示操作成功的模式。

剩下的另外兩個(gè)操作彼此類似,所以讓我們看看導(dǎo)入數(shù)據(jù)。

如果用戶點(diǎn)擊相應(yīng)的按鈕,則會(huì)發(fā)出一個(gè)事件(onclick={() => EventsEmit("import_data")}),該事件在后端監(jiān)聽。收到后,將打開本機(jī)選擇文件對(duì)話框以允許用戶選擇備份文件。如果用戶選擇文件,包含路徑(fileLocation)的變量將不包含空字符串,這將在后端觸發(fā)一個(gè)事件(“enter_password”),該事件現(xiàn)在在前端偵聽,然后顯示一個(gè)新的彈出窗口詢問導(dǎo)出時(shí)使用的主密碼。同樣,前端將發(fā)出另一個(gè)事件(“密碼”),其中攜帶用戶輸入的主密碼。當(dāng)后端接收到這個(gè)新事件時(shí),會(huì)執(zhí)行 Db 包的 ImportDump 方法,該方法執(zhí)行從用戶選擇的備份文件中讀取和恢復(fù) DB 中的數(shù)據(jù)的工作。結(jié)果,發(fā)出一個(gè)新事件(“imported_data”),該事件將其執(zhí)行結(jié)果(成功或不成功)作為附加數(shù)據(jù)攜帶。前端收到事件后只需執(zhí)行 2 個(gè)任務(wù):

  • 如果結(jié)果成功,請(qǐng)?jiān)O(shè)置備份文件中保存的語言并顯示指示操作成功的模式
  • 如果由于某種原因無法完成導(dǎo)入,請(qǐng)顯示錯(cuò)誤及其原因。

所有這些在代碼邏輯中比用文字解釋要容易得多?:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

值得一提的是,在前端注冊偵聽器的 Wails 運(yùn)行時(shí)函數(shù) (EventsOn) 返回一個(gè)函數(shù),該函數(shù)在調(diào)用時(shí)會(huì)取消所述偵聽器。當(dāng)組件被銷毀時(shí),取消所述監(jiān)聽器是很方便的。與 React 類似,onMount 鉤子可以通過讓監(jiān)聽器返回一個(gè)清理函數(shù)來“清理”它們,在這種情況下,該函數(shù)將調(diào)用 EventsOn 返回的所有函數(shù),我們已采取預(yù)防措施將其保存在單獨(dú)的文件中。變量:

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

為了完成對(duì)我們應(yīng)用程序前端部分的審查,只需介紹一下“關(guān)于”組件即可。這幾乎沒有邏輯,因?yàn)樗鼉H限于顯示有關(guān)應(yīng)用程序的信息,就像常見的 about 一樣。然而,應(yīng)該說,正如我們所看到的,該視圖顯示了指向應(yīng)用程序存儲(chǔ)庫的鏈接。顯然,在普通網(wǎng)頁中,錨標(biāo)記 () 將使我們導(dǎo)航到相應(yīng)的鏈接,但在桌面應(yīng)用程序中,如果 Wails 在運(yùn)行時(shí)沒有為此提供特定函數(shù) (BrowserOpenURL),則不會(huì)發(fā)生這種情況:

/* package.json */
...
},
  "dependencies": {
    "svelte-copy": "^2.0.0",
    "svelte-i18n": "^4.0.1",
    "svelte-spa-router": "^4.0.1",
    "sweetalert2": "^11.14.5"
  }
...

這會(huì)將二進(jìn)制文件構(gòu)建到 build/bin 文件夾中。但是,要選擇其他構(gòu)建選項(xiàng)或執(zhí)行交叉編譯,您可能需要查看 Wails CLI 文檔。

對(duì)于這個(gè)應(yīng)用程序,我想我已經(jīng)在本系列的第一部分中提到過,我只關(guān)注Windows和Linux的編譯。為了以舒適的方式執(zhí)行這些任務(wù)(由于測試,這些任務(wù)是重復(fù)的),我創(chuàng)建了一些小腳本和一個(gè)“協(xié)調(diào)”它們的 Makefile。

make create-bundles 命令為 Linux 版本創(chuàng)建一個(gè) .tar.xz 壓縮文件,其中包含應(yīng)用程序和一個(gè)充當(dāng)安裝可執(zhí)行文件的“安裝程序”的 Makefile,一個(gè)用于在 開始菜單以及相應(yīng)的應(yīng)用程序圖標(biāo)。對(duì)于 Windows 版本,二進(jìn)制文件只是在名為 dist/ 的文件夾中壓縮為 .zip。但是,如果您更喜歡跨平臺(tái)自動(dòng)構(gòu)建,Wails 有一個(gè) Github Actions,允許您上傳(默認(rèn)選項(xiàng))生成的工件到您的存儲(chǔ)庫。

請(qǐng)注意,如果您在運(yùn)行時(shí)使用 make create-bundles 命令,它將調(diào)用 Wails 命令 wails build -clean -upx (對(duì)于 Linux)或 wails build -skipbindings -s -platform windows/amd64 - upx(對(duì)于 Windows)。 -upx 標(biāo)志是指使用您應(yīng)該安裝在計(jì)算機(jī)上的

UPX 實(shí)用程序來壓縮二進(jìn)制文件??蓤?zhí)行文件體積小的部分秘密是由于該實(shí)用程序所做的出色的壓縮工作。

最后,請(qǐng)注意,構(gòu)建腳本會(huì)自動(dòng)將當(dāng)前存儲(chǔ)庫標(biāo)簽添加到“關(guān)于”視圖,并在構(gòu)建后將其值恢復(fù)為默認(rèn)值 (DEV_VERSION)。

唷!這兩篇文章比我想象的要長!但我希望您喜歡它們,最重要的是,它們可以幫助您思考新項(xiàng)目。在編程中學(xué)習(xí)一些東西就像這樣......

請(qǐng)記住,您可以在此 GitHub 存儲(chǔ)庫中找到所有應(yīng)用程序代碼。

我相信我會(huì)在其他帖子中見到你。編碼愉快??。?/p>

以上是極簡密碼管理器桌面應(yīng)用程序:進(jìn)軍 Golang 的 Wails 框架(第 2 部分)的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

默認(rèn)情況下,GO靜態(tài)鏈接的含義是什么? 默認(rèn)情況下,GO靜態(tài)鏈接的含義是什么? Jun 19, 2025 am 01:08 AM

Go默認(rèn)將程序編譯為獨(dú)立二進(jìn)制文件,主要原因是靜態(tài)鏈接。1.部署更簡單:無需額外安裝依賴庫,可直接跨Linux發(fā)行版運(yùn)行;2.二進(jìn)制體積更大:包含所有依賴導(dǎo)致文件尺寸增加,但可通過構(gòu)建標(biāo)志或壓縮工具優(yōu)化;3.更高的可預(yù)測性與安全性:避免外部庫版本變化帶來的風(fēng)險(xiǎn),增強(qiáng)穩(wěn)定性;4.運(yùn)行靈活性受限:無法熱更新共享庫,需重新編譯部署以修復(fù)依賴漏洞。這些特性使Go適用于CLI工具、微服務(wù)等場景,但在存儲(chǔ)受限或依賴集中管理的環(huán)境中需權(quán)衡取舍。

如何在GO中創(chuàng)建緩沖頻道? (例如,make(chan int,10)) 如何在GO中創(chuàng)建緩沖頻道? (例如,make(chan int,10)) Jun 20, 2025 am 01:07 AM

在Go中創(chuàng)建緩沖通道只需在make函數(shù)中指定容量參數(shù)即可。緩沖通道允許發(fā)送操作在沒有接收者時(shí)暫存數(shù)據(jù),只要未超過指定容量,例如ch:=make(chanint,10)創(chuàng)建了一個(gè)可存儲(chǔ)最多10個(gè)整型值的緩沖通道;與無緩沖通道不同,發(fā)送數(shù)據(jù)時(shí)不會(huì)立即阻塞,而是將數(shù)據(jù)暫存于緩沖區(qū)中,直到被接收者取走;使用時(shí)需注意:1.容量設(shè)置應(yīng)合理以避免內(nèi)存浪費(fèi)或頻繁阻塞;2.需防止緩沖區(qū)無限堆積數(shù)據(jù)導(dǎo)致內(nèi)存問題;3.可用chanstruct{}類型傳遞信號(hào)以節(jié)省資源;常見場景包括控制并發(fā)數(shù)量、生產(chǎn)者-消費(fèi)者模型及異

在沒有C中的手動(dòng)內(nèi)存管理的情況下,如何確保內(nèi)存安全性? 在沒有C中的手動(dòng)內(nèi)存管理的情況下,如何確保內(nèi)存安全性? Jun 19, 2025 am 01:11 AM

Goensuresmemorysafetywithoutmanualmanagementthroughautomaticgarbagecollection,nopointerarithmetic,safeconcurrency,andruntimechecks.First,Go’sgarbagecollectorautomaticallyreclaimsunusedmemory,preventingleaksanddanglingpointers.Second,itdisallowspointe

如何使用GO進(jìn)行系統(tǒng)編程任務(wù)? 如何使用GO進(jìn)行系統(tǒng)編程任務(wù)? Jun 19, 2025 am 01:10 AM

Go是系統(tǒng)編程的理想選擇,因?yàn)樗Y(jié)合了C等編譯型語言的性能與現(xiàn)代語言的易用性和安全性。1.文件與目錄操作方面,Go的os包支持創(chuàng)建、刪除、重命名及檢查文件和目錄是否存在,使用os.ReadFile可一行代碼讀取整個(gè)文件,適用于編寫備份腳本或日志處理工具;2.進(jìn)程管理方面,通過os/exec包的exec.Command函數(shù)可執(zhí)行外部命令、捕獲輸出、設(shè)置環(huán)境變量、重定向輸入輸出流以及控制進(jìn)程生命周期,適合用于自動(dòng)化工具和部署腳本;3.網(wǎng)絡(luò)與并發(fā)方面,net包支持TCP/UDP編程、DNS查詢及原始套

如何在GO中的結(jié)構(gòu)實(shí)例上調(diào)用方法? 如何在GO中的結(jié)構(gòu)實(shí)例上調(diào)用方法? Jun 24, 2025 pm 03:17 PM

在Go語言中,調(diào)用結(jié)構(gòu)體方法需先定義結(jié)構(gòu)體和綁定接收者的方法,使用點(diǎn)號(hào)訪問。定義結(jié)構(gòu)體Rectangle后,可通過值接收者或指針接收者聲明方法;1.使用值接收者如func(rRectangle)Area()int,通過rect.Area()直接調(diào)用;2.若需修改結(jié)構(gòu)體,應(yīng)使用指針接收者如func(r*Rectangle)SetWidth(...),Go會(huì)自動(dòng)處理指針與值的轉(zhuǎn)換;3.嵌入結(jié)構(gòu)體時(shí),內(nèi)嵌結(jié)構(gòu)體的方法會(huì)被提升,可直接通過外層結(jié)構(gòu)體調(diào)用;4.Go無需強(qiáng)制使用getter/setter,字

GO中的接口是什么?如何定義它們? GO中的接口是什么?如何定義它們? Jun 22, 2025 pm 03:41 PM

在Go語言中,接口是一種定義行為而不指定實(shí)現(xiàn)方式的類型。接口由方法簽名組成,任何實(shí)現(xiàn)這些方法的類型都自動(dòng)滿足該接口。例如,定義一個(gè)Speaker接口包含Speak()方法,則所有實(shí)現(xiàn)該方法的類型均可視為Speaker。接口適用于編寫通用函數(shù)、抽象實(shí)現(xiàn)細(xì)節(jié)和測試中使用mock對(duì)象。定義接口使用interface關(guān)鍵字并列出方法簽名,無需顯式聲明類型實(shí)現(xiàn)了接口。常見用例包括日志、格式化、不同數(shù)據(jù)庫或服務(wù)的抽象,以及通知系統(tǒng)等。例如,Dog和Robot類型均可實(shí)現(xiàn)Speak方法,并傳遞給同一個(gè)Anno

如何在GO中使用字符串軟件包中的字符串函數(shù)? (例如len(),strings.contains(),strings.index(),strings.replaceall()) 如何在GO中使用字符串軟件包中的字符串函數(shù)? (例如len(),strings.contains(),strings.index(),strings.replaceall()) Jun 20, 2025 am 01:06 AM

在Go語言中,字符串操作主要通過strings包和內(nèi)置函數(shù)實(shí)現(xiàn)。1.strings.Contains()用于判斷字符串是否包含子串,返回布爾值;2.strings.Index()可查找子串首次出現(xiàn)的位置,若不存在則返回-1;3.strings.ReplaceAll()能替換所有匹配的子串,還可通過strings.Replace()控制替換次數(shù);4.len()函數(shù)用于獲取字符串字節(jié)數(shù)長度,但處理Unicode時(shí)需注意字符與字節(jié)的區(qū)別。這些功能常用于數(shù)據(jù)過濾、文本解析及字符串處理等場景。

如何使用IO軟件包在GO中使用輸入和輸出流? 如何使用IO軟件包在GO中使用輸入和輸出流? Jun 20, 2025 am 11:25 AM

TheGoiopackageprovidesinterfaceslikeReaderandWritertohandleI/Ooperationsuniformlyacrosssources.1.io.Reader'sReadmethodenablesreadingfromvarioussourcessuchasfilesorHTTPresponses.2.io.Writer'sWritemethodfacilitateswritingtodestinationslikestandardoutpu

See all articles