"with"함수 패턴을 사용하여 정리 논리를 통합하는 방법

6256 단어
내 팀원 중 일부는 "with"함수 패턴과 적절한 리소스 정리를 보장하는 것이 얼마나 편리한지 좋아했습니다.

"with"함수는 콜백을 받아 일부 초기화를 수행하고 콜백을 호출한 다음 일부 정리를 수행합니다.

예를 들어, 다음과 같이 모든 SQL 트랜잭션에 대해 수동으로 COMMIT 또는 ROLLBACK를 수행하는 대신:

tx, err := db.Begin()
if err != nil {
    return err
}

err = tx.Exec("INSERT ...")
if err != nil {
    // 💥 Oops, forgot tx.Rollback(), tx remains open!
    return err
}

// execute more statements...

err = tx.Commit()
if err != nil {
    return err
}

withTx() 함수를 만들 수 있습니다.

func withTx(db DB, callback func(Tx) error) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()

    err = callback(tx)
    if err != nil {
        return err
    }

    return tx.Commit()  
}


다음과 같이 사용하십시오.

err := withTx(db, func(tx Tx) error {
    err = tx.Exec("INSERT ...")
    if err != nil {
        // 🙂 No need to remember to call tx.Rollback()
        return err
    }
    // execute more statements...
})
if err != nil {
    return err
}


언뜻 보기에 calls ~ Begin()의 ~5%는 오류( likely example )에서 해당하는 Rollback()가 누락된 것으로 보입니다. withTx() 함수를 사용하면 이러한 버그를 제거하는 데 도움이 됩니다.

그리고 Go 제네릭을 사용하면 withTx에서 값을 반환할 수 있습니다.

-func withTx(db DB, callback func(Tx) error) error {
+func withTx[T any](db DB, callback func(Tx) (*T, error)) (*T, error) {
    tx, err := db.Begin()
    if err != nil {
-       return err
+       return nil, err
    }
    defer tx.Rollback()

-   err = callback(tx)
+   t, err := callback(tx)
    if err != nil {
        return err
    }

-   return tx.Commit()
+   return t, tx.Commit()
 }


"with"함수 패턴의 이점:
  • 자동 초기화 및 정리
  • 적은 코드
  • 경우에 따라 작업이 성공했는지 확인하고 성공하지 못한 경우 다른 작업을 수행할 필요가 없습니다
  • .

    명심해야 할 한 가지 주의 사항: 콜백이 리소스를 반환하지 않는지 확인해야 합니다. 그렇지 않으면 정리 실행 후 해당 리소스가 사용되어 오류가 발생할 수 있습니다! Go에서 컴파일 타임에 올바른 사용을 강제하는 것이 가능하다고 생각하지 않습니다. 그것은 Haskell에서 가능하지만(인체공학적이지는 않음) 내장된 가치 평생 기계에 편승하여 Rust에서 편리합니다.

    좋은 웹페이지 즐겨찾기