Golang의 불변성
불변성을 사용하여 Golang 애플리케이션의 가독성과 안정성을 높이는 방법
불변성의 개념은 매우 간단합니다. 객체(또는 구조)를 만든 후에는 불가능합니다. 개념은 단순해 보이지만 이를 사용하거나 활용하기는 쉽지 않습니다.
컴퓨터 과학(및 생활)의 대부분과 마찬가지로 이를 수행하는 방법은 많습니다. 동일한 결과를 얻을 수 있으며 불변성 측면에서는 차이가 없습니다. 이를 툴킷의 도구로 생각하고 적용 가능한 문제 시나리오에 사용해야 합니다. 불변성에 대한 매우 좋은 사용 사례는 동시 프로그래밍을 수행할 때입니다.
어떤 패러다임을 사용하든 다음 방법을 사용하여 Golang에서 일부 불변성 개념을 사용할 수 있습니다. 코드는 더 읽기 쉽고 안정적입니다. 구조체의 함수는 해당 필드가 아닌 내보내집니다.
이는 캡슐화와 유사합니다. 내보내지 않은 필드가 있는 구조체를 만들고 작동하는 함수만 내보내므로 해당 구조의 동작이 중요합니다. 이 기술은 인터페이스에 매우 유용합니다. 이 기술에 대한 또 다른 좋은 추가 사항은 생성 함수(또는 생성자)를 구조에 추가하고 내보내는 것입니다. 이렇게 하면 상태가 항상 유효하게 유지됩니다. 구조에 대해 수행하려는 모든 작업에 대해 잘못된 상태를 계속 처리할 필요가 없기 때문에 코드가 더 안정적입니다. 다음은 매우 기본적인 예입니다. package amounts
import "errors"
type Amount struct {
value int
}
func NewAmount(value int) (Amount, error) {
if value
이 패키지에서는 Amount
를 정의합니다. 내보내지 않은 필드 value
, 생성자 NewAmount
및 Amount
유형에 대한 GetValue
메서드가 있는 유형입니다. 함수는 Amount
구조를 생성하므로 변경할 수 없습니다. 따라서 패키지 외부에서 변경할 수 없습니다(go 2에서는 이를 변경하라는 제안이 있지만 변경 불가능을 생성할 수 있는 방법은 없습니다). go 1)의 구조. 또한 잘못된 상태(이 경우 음수)인 Amount
유형의 변수가 없습니다. 이를 생성하는 유일한 방법이 확인되었기 때문입니다. 다른 패키지에서 가져왔습니다:
a, err := amounts.NewAmount(10) *// 处理错误 *log.Println(a.GetValue())
함수에서 포인터 대신 값 복사본 사용Amount
类型, 具有未导出的字段 value
, 构造函数 NewAmount
以及 GetValue
方法用于 Amount
类型. 一旦 NewAmount
函数创建了 Amount
结构, 就无法更改它. 因此它从包的外部来说是不可变的 (尽管在 go 2 中有 更改此内容的建议, 但 go 1 中没有创建不变结构的方法). 此外没有处于无效状态 (在这种情况下为负数) 的 Amount
类型的变量, 因为创建它们的唯一方法已经对此进行了验证. 我们可以从另一个包中调用它:
package accounts import ( "errors" "my-package/amounts" ) type Account struct { balance amounts.Amount } func NewEmptyAccount() Account { amount, _ := amounts.NewAmount(0) return NewAccount(amount) } func NewAccount(amount amounts.Amount) Account { return Account{balance: amount} } func (acc Account) Deposit(amount amounts.Amount) Account { newAmount, _ := amounts.NewAmount(acc.balance.GetValue() + amount.GetValue()) acc.balance = newAmount return acc } func (acc Account) Withdraw(amount amounts.Amount) (Account, error) { newAmount, err := amounts.NewAmount(acc.balance.GetValue() - amount.GetValue()) if err != nil { return acc, errors.New("Insuficient funds") } acc.balance = newAmount return acc, nil }
在函数中使用值拷贝替代指针
最基本的概念是在创建一个对象(或者结构体)后,再也不去改变它。但是我们经常在实体状态很重要的应用上工作。不过,程序中实体状态和实体内部表示是不同的。在使用不变性时,我们仍然可以给实体赋予多个状态。这意味着已创建的结构体不会改变,但是它的副本会改变。这并不意味着我们需要手动实现复制结构体中每个字段的功能。
相反地,当调用函数时我们可以依赖 Go 语言复制值的本机行为。对于任意一个会改变实体状态的操作,我们可以创建一个用来接收结构体作为参数(或者作为函数接收器)的函数,在执行完毕之后返回改变后的版本。这是一项非常强大的技术,因为你能够改变副本上的任何内容,而无需更改函数调用者作为参数传递的变量。这意味着没有副作用和可预测的行为。如果相同的结构体被传递给并发函数,每个结构体都会接收到它的副本,而不是指向它的指针。
当你在使用切片功能时,你会看到此行为应用于 [append](https://golang.org/pkg/builtin/#append)
函数
回到我们的例子中,让我们实现 Account
类型,它包含了Amount
类型的 balance
字段。同时,我们添加 Deposit
和 Withdraw
方法来改变 Account
实体的状态。
a, err := amounts.NewAmount(10) acc := accounts.NewEmptyAccount() acc2 := acc.Deposit(a) log.Println(acc.GetBalance()) log.Println(acc2.GetBalance())
如果你检查我们创建的方法,他们会觉得我们事实上改变了作为函数接收器的 Account
结构的状态。由于我们没有使用指针,情况并非如此,由于结构体的副本作为这些函数的接收器来传递,我们将更改只在函数作用域内有效的副本,然后返回它。这是在另一个包中调用它的示例:
2020/06/03 22:22:40 {0} 2020/06/03 22:22:40 {10}
命令行上的结果会是这样的:
package main import ( "fmt" "time" ) var rand int = 0 func main() { rand = time.Now().Second() + 1 fmt.Println(sum(1, 2)) } func sum(a, b int) int { return a + b + rand }
如你所见,尽管通过变量 acc
调用了 Deposit
方法,但实际上变量并没有改变,它返回了新的 Account
副本(分配给 acc2
[append](https://golang.org/pkg/builtin/#append)
기능에 이 동작이 적용되는 것을 볼 수 있습니다. 🎜🎜Back to us 이 예에서는 Amount
유형의 balance
필드가 포함된 Account
유형을 구현해 보겠습니다. 동시에 Deposit
및 Withdraw
메서드를 추가하여 Account
엔터티의 상태를 변경합니다. 🎜func sum(a, b, rand **int**) **int** { return a + b + rand }🎜우리가 생성한 메서드를 살펴보면 함수의 수신자인
Account
구조의 상태를 실제로 변경하고 있는 것으로 보입니다. 포인터를 사용하지 않기 때문에 그렇지 않으며 구조체의 복사본이 이러한 함수의 수신자로 전달되므로 함수 범위 내에서만 유효한 복사본을 변경한 다음 반환합니다. 다음은 다른 패키지에서 이를 호출하는 예입니다. 🎜rrreee🎜명령줄의 결과는 다음과 같습니다. 🎜rrreee🎜보시다시피 Deposit은 <code>acc
변수를 통해 호출됩니다. 메서드를 사용했지만 변수가 실제로 변경되지 않은 경우 변경된 필드가 포함된 Account
(acc2
에 할당됨)의 새 복사본을 반환합니다. 🎜使用指针具有优于复制值的优点,特别是如果您的结构很大时,在复制时可能会导致性能问题,但是您应始终问自己是否值得,不要尝试过早地优化代码。尤其是在使用并发时。您可能会在一些糟糕的情况下结束。
减少全局或外部状态中的依赖性
不变性不仅可以应用于结构,还可以应用于函数。如果我们用相同的参数两次执行相同的函数,我们应该收到相同的结果,对吗?好吧,如果我们依赖于外部状态或全局变量,则可能并非总是如此。最好避免这种情况。有几种方法可以实现这一目标。
如果您在函数内部使用共享的全局变量,请考虑将该值作为参数传递,而不是直接在函数内部使用。 那会使您的函数更可预测,也更易于测试。整个代码的可读性也会更容易,其他人也将会了解到值可能会影响函数行为,因为它是一个参数,而这就是参数的用途。 这里有一个例子:
package main import ( "fmt" "time" ) var rand int = 0 func main() { rand = time.Now().Second() + 1 fmt.Println(sum(1, 2)) } func sum(a, b int) int { return a + b + rand }
这个函数 sum
使用全局变量作为自己计算的一部分。 从函数签名来看这不是很清楚。 更好的方法是将rand变量作为参数传递。 因此该函数看起来应该像这样:
func sum(a, b, rand **int**) **int** { return a + b + rand }
推荐教程:《Go教程》
위 내용은 Go의 불변 유형에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

toensureInitFunctionSareefeCectiveAdaintainable : 1) minimizesideFectsByReTurningValuesInsteAdglobalstate, 2) inficeDempotencyToHandleMultipLecallsSafely 및 3) BRALKTODDOCLEXINITIANSETSMALLER, FOCUSISSEDFUNCINTURATURITYANDUMALOMODUMALEDUMAL ANDM

goisidealforbeginnersandsuitableforcloudandnetworkservicesduetoitssimplicity, 효율성, 및 콘크리 론 피처

개발자는 다음과 같은 모범 사례를 따라야합니다. 1. 자원 누출을 방지하기 위해 조롱 틴을 신중하게 관리합니다. 2. 동기화를 위해 채널을 사용하지만 과용을 피하십시오. 3. 동시 프로그램의 오류를 명시 적으로 처리합니다. 4. 성능을 최적화하기 위해 GomaxProc을 이해하십시오. 이러한 관행은 효율적이고 강력한 소프트웨어 개발에 효과적이며 자원의 효과적인 관리, 적절한 동기화 구현, 적절한 오류 처리 및 성능 최적화를 보장하여 소프트웨어 효율성 및 유지 관리 가능성을 향상시킬 수 있기 때문입니다.

goexcelsinproductionduetoitsperformanceandsimplicity, butrequirescarefulmanagementibility, errorhandling, andresources

표준 오류 인터페이스가 제한된 정보를 제공하고 사용자 정의 유형이 더 많은 컨텍스트와 구조화 된 정보를 추가 할 수 있으므로 오류 유형을 사용자 정의해야합니다. 1) 사용자 정의 오류 유형에는 오류 코드, 위치, 컨텍스트 데이터 등이 포함될 수 있습니다. 2) 디버깅 효율성 및 사용자 경험 향상, 3) 복잡성 및 유지 보수 비용에주의를 기울여야합니다.

goisidealforbuildingscalablesystemsduetoitssimplicity, 효율성 및 빌드-내부 컨 컨 오렌 스upport.1) go'scleansyntaxandminimalisticdesignenenhance-reductivityandreduceerrors.2) itsgoroutinesandChannelsableefficedsoncurrentProgramming, DistributingLoa

initTectionsIntOnaUtomaticallyBeforemain () andAreSefulforsettingupenvirondentAnitializingVariables.usethemforsimpletasks, propoysideeffects 및 withtestingntestingandloggingtomaincodeclarityAndestability.

goinitializespackages는 theyareimported, theexecutesinitfunctions, theneiredefinitionorder, andfilenamesDeterMineDeTerMineTeRacrossMultipleFiles.ThemayLeadTocomplexInitializations의 의존성 의존성의 의존성을 확인합니다


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구

Eclipse용 SAP NetWeaver 서버 어댑터
Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기
