Go: كيفية استخدام القيم الصفرية دون استخدام أنواع المراجع



بناء على صور من gopherize.me



في كثير من الأحيان من كود Go ، يتعين علينا العمل مع العديد من واجهات برمجة تطبيقات HTTP أو العمل كخدمة HTTP بأنفسنا.



واحدة من أكثر الحالات شيوعًا: نتلقى البيانات في شكل هيكل من قاعدة البيانات ، ونرسل الهيكل إلى واجهة برمجة التطبيقات الخارجية ، واستجابة لذلك نتلقى بنية أخرى ، ونحولها بطريقة ما ونحفظها في قاعدة البيانات.



بمعنى آخر: لا تتطلب هذه المعالجة العديد من العمليات المنفصلة مع هياكل الطلب والاستجابة.



من الطبيعي أن يكون لواجهات برمجة التطبيقات حقول في هياكل الطلب والاستجابة يمكن أن تكون صفرية ويمكن أن تأخذ بعض القيم غير الصفرية. عادة ما تبدو مثل هذه الهياكل مثل هذا



type ApiResponse struct {
  Code *string json:"code"`
}


ولأنه نوع مرجعي ، يقوم مترجم Go بتحليل الهروب ويمكنه نقل المتغير المحدد إلى الكومة. في حالة الإنشاء المتكرر لمثل هذه المتغيرات ، نحصل على حمل إضافي على GC ويمكننا حتى الحصول على "تسرب للذاكرة" إذا لم يكن لدى GC الوقت لتحرير كل الذاكرة المستخدمة.



ما الذي يمكن عمله في مثل هذه الحالة:



  • قم بتعديل واجهة برمجة التطبيقات الخارجية بحيث لا تستخدم قيم صفرية. في بعض الأحيان يكون هذا مقبولًا ، ولكن تغيير واجهة برمجة التطبيقات ليس دائمًا فكرة جيدة: أولاً ، هذا عمل إضافي ، وثانيًا ، الأخطاء التي قد تظهر من إعادة العمل هذه.
  • قم بتعديل كود Go الخاص بنا حتى نتمكن من قبول قيم صفرية ، لكن لا تستخدم أنواع المراجع لذلك.


, " "



.



Go



type pointerSmall struct {
 Field000 *string
 Field001 *string
 Field002 *string
 Field003 *string
 Field004 *string
 Field005 *string
}


,



type valueSmall struct {
 Field000 string
 Field001 string
 Field002 string
 Field003 string
 Field004 string
 Field005 string
}


0 , .

, .



: Go, ( - ) .



— . , . . — . , .. Go .



— , . , .



BenchmarkPointerSmall-8    1000000000          0.295 ns/op        0 B/op        0 allocs/op
BenchmarkValueSmall-8      184702404          6.51 ns/op        0 B/op        0 allocs/op


. , - - .



BenchmarkPointerSmallChain-8    1000000000          0.297 ns/op        0 B/op        0 allocs/op
BenchmarkValueSmallChain-8      59185880         20.3 ns/op        0 B/op        0 allocs/op


JSON . , jsoniter. . , .



BenchmarkPointerSmallJSON-8       49522      23724 ns/op    14122 B/op       28 allocs/op
BenchmarkValueSmallJSON-8         52234      22806 ns/op    14011 B/op       15 allocs/op


, easyjson. , .



BenchmarkPointerSmallEasyJSON-8       64482      17815 ns/op    14591 B/op       21 allocs/op
BenchmarkValueSmallEasyJSON-8         63136      17537 ns/op    14444 B/op       14 allocs/op


: , . (/ ) — .



.



type pointerBig struct {
 Field000 *string
 ...
 Field999 *string
}

type valueBig struct {
 Field000 string
 ...
 Field999 string
}


. , 0 , ( , .. ). , :



BenchmarkPointerBig-8       36787      32243 ns/op    24192 B/op     1001 allocs/op
BenchmarkValueBig-8        721375       1613 ns/op        0 B/op        0 allocs/op


. . ( , ).



BenchmarkPointerBigChain-8       36607      31709 ns/op    24192 B/op     1001 allocs/op
BenchmarkValueBigChain-8        351693       3216 ns/op        0 B/op        0 allocs/op


.



BenchmarkPointerBigJSON-8         250    4640020 ns/op  5326593 B/op     4024 allocs/op
BenchmarkValueBigJSON-8           270    4289834 ns/op  4110721 B/op     2015 allocs/op


, easyjson. . , jsoniter.



BenchmarkPointerBigEasyJSON-8         364    3204100 ns/op  2357440 B/op     3066 allocs/op
BenchmarkValueBigEasyJSON-8           380    3058639 ns/op  2302248 B/op     1063 allocs/op


: — , . — " ". (easyjson ), — .





— Nullable . sql — sql.NullBool, sql.NullString .



أيضًا ، بالنسبة للنوع ، ستحتاج إلى وصف وظائف التشفير وفك التشفير.



func (n NullString) MarshalJSON() ([]byte, error) {
    if !n.Valid {
        return []byte("null"), nil
    }

    return jsoniter.Marshal(n.String)
}

func (n *NullString) UnmarshalJSON(data []byte) error {
    if bytes.Equal(data, []byte("null")) {
        *n = NullString{}
        return nil
    }

    var res string

    err := jsoniter.Unmarshal(data, &res)
    if err != nil {
        return err
    }

    *n = NullString{String: res, Valid: true}

    return nil
}


كنتيجة للتخلص من أنواع المراجع في API - قمت بتطوير مكتبة نانوية ، مع أنواع Nullable الأساسية مع وظائف التشفير وفك التشفير لـ JSON و jsoniter و easyjson و gocql.



سهولة استخدام أنواع Nullable



وأحد الأسئلة الأخيرة التي يمكنك طرحها حول التبديل إلى أنواع Nullable هو ما إذا كانت ملائمة للاستخدام.



رأيي الشخصي مناسب ، الأنواع لها نفس نمط الاستخدام مثل المراجع المتغيرة.



عند استخدام ارتباط ، نكتب



if a != nil && *a == "sometext" {


مع نوع Nullable ، نكتب



if a.Valid && a.String == "sometext" {



All Articles