পুনরাবৃত্তি করার সময় মান পরিবর্তন করুন


153

ধরা যাক আমার কাছে এই ধরণের রয়েছে:

type Attribute struct {
    Key, Val string
}
type Node struct {
    Attr []Attribute
}

এবং আমার নোডের বৈশিষ্ট্যগুলি সেগুলি পরিবর্তন করতে আমি পুনরাবৃত্তি করতে চাই।

আমি করতে সক্ষম হতে চাই:

for _, attr := range n.Attr {
    if attr.Key == "href" {
        attr.Val = "something"
    }
}

তবে attrএটি কোনও পয়েন্টার হিসাবে নয়, এটি কাজ করবে না এবং আমাকে করতে হবে:

for i, attr := range n.Attr {
    if attr.Key == "href" {
        n.Attr[i].Val = "something"
    }
}

কোন সহজ বা দ্রুততর উপায় আছে? এটি থেকে সরাসরি পয়েন্টার পাওয়া সম্ভব range?

স্পষ্টতই আমি কাঠামোগুলি কেবল পুনরাবৃত্তির জন্য পরিবর্তন করতে চাই না এবং আরও ভার্বোজের সমাধানগুলি কোনও সমাধান নয়।


2
সুতরাং আপনি Array.prototype.forEachজাভাস্ক্রিপ্ট কিছু ধরণের চান ?
ফ্লোরিয়ান মার্জাইন

এটি একটি আকর্ষণীয় ধারণা এবং এটি একটি সমাধান হতে পারে তবে একটি ফাংশন কল করে যা প্রতিটি পুনরাবৃত্তিতে কোনও ফাংশনকে কল করে যা সার্ভারের পাশের ভাষায় ভারী এবং ভুল দেখাচ্ছে। এবং জেনেরিকের অভাব এই অনুভূতিটিকে আরও ভারী করে তুলবে।
অস্বীকার করেন সাগুরেট

সত্যিই, আমি মনে করি না যে এটি এত ভারী। একটি ফাংশন বা দুটি কল করা খুব সস্তা, এটি সাধারণত কম্পাইলাররা সর্বাধিক অনুকূলিত করে। আমি এটি চেষ্টা করে দেখতে চাই এবং এটি বিলটি ফিট করে কিনা তা দেখতে বেঞ্চমার্ক করব।
ফ্লোরিয়ান মার্জাইন

গো জেনেরিকের অভাব হওয়ায়, আমি ভয় করি যে ফাংশনটি পাস হয়েছে forEachঅগত্যা কোনও প্রকারের দৃ .়তার সাথে শুরু হবে। এটি এর চেয়ে সত্যই ভাল নয় attr := &n.Attr[i]
সাগুরেট

উত্তর:


152

না, আপনি যে সংক্ষিপ্তসারটি চান তা সম্ভব নয়।

এর কারণ হ'ল আপনি যে rangeস্লাইসটি পুনরাবৃত্তি করছেন সেগুলি থেকে মানগুলি অনুলিপি করে। পরিসর সম্পর্কে স্পেসিফিকেশন বলেছেন:

Range expression                          1st value             2nd value (if 2nd variable is present)
array or slice  a   [n]E, *[n]E, or []E   index    i  int       a[i]       E

সুতরাং, পরিসীমাটি a[i]অ্যারে / স্লাইসগুলির জন্য এটির দ্বিতীয় মান হিসাবে ব্যবহার করে , যার কার্যকরভাবে অর্থ হল যে মানটি অনুলিপি করা হয়েছে, আসল মানটিকে অস্পৃশ্য করে তোলে।

এই আচরণটি নিম্নলিখিত কোড দ্বারা প্রদর্শিত হয় :

x := make([]int, 3)

x[0], x[1], x[2] = 1, 2, 3

for i, val := range x {
    println(&x[i], "vs.", &val)
}

কোডটি পরিসীমা থেকে মান এবং স্লাইসে আসল মানটির জন্য আপনাকে সম্পূর্ণ আলাদা মেমরি অবস্থানগুলি ছাপায়:

0xf84000f010 vs. 0x7f095ed0bf68
0xf84000f014 vs. 0x7f095ed0bf68
0xf84000f018 vs. 0x7f095ed0bf68

সুতরাং আপনি যা করতে পারেন তা হ'ল হয় পয়েন্টার বা সূচি ব্যবহার করা, যেমন ইতিমধ্যে জেএনএমএল এবং পিটারসো দ্বারা প্রস্তাবিত।


16
এটি ভাবার একটি উপায় হ'ল মান নির্ধারণের ফলে অনুলিপি হয়। আপনি যদি ভাল: = x [1] দেখে থাকেন তবে এটি পুরোপুরি আশ্চর্যজনক হবে যে ভলটি এক্স [1] এর একটি অনুলিপি ছিল। বিশেষ কিছু করার জন্য পরিসীমাটি ভাবার পরিবর্তে, মনে রাখবেন যে পরিসরের প্রতিটি পুনরাবৃত্তি সূচী এবং মান ভেরিয়েবলগুলি নির্ধারিত করে শুরু হয় এবং অনুলিপিটি অনুলিপিটির কারণের পরিবর্তে হয়।
অ্যান্ডি ডেভিস

দুঃখিত আমি এখনও কিছুটা বিভ্রান্ত এখানে। যদি লুপের 2 য় মানটি একটি [i] হয়, তবে a[i]লুপ এবং a[i]আমরা যেভাবে লিখছি তার মধ্যে কী আলাদা ? দেখতে দেখতে একই জিনিস লাগছে ঠিক তাই না?
টিয়ান এনগুইন হোইং

1
@ TiếnNguyễnHoàng rangeআয় a[i]তার দ্বিতীয় ফেরত মান হিসাবে। এই অপারেশনটি val = a[i]যেমন rangeমানটির একটি অনুলিপি তৈরি করে তাই কোনও লিখিত ক্রিয়াকলাপ valঅনুলিপি প্রয়োগ করা হয়।
নিমো

37

আপনি এর সমতুল্য কিছু চাইছেন বলে মনে হচ্ছে:

package main

import "fmt"

type Attribute struct {
    Key, Val string
}
type Node struct {
    Attr []Attribute
}

func main() {

    n := Node{
        []Attribute{
            {"key", "value"},
            {"href", "http://www.google.com"},
        },
    }
    fmt.Println(n)

    for i := 0; i < len(n.Attr); i++ {
        attr := &n.Attr[i]
        if attr.Key == "href" {
            attr.Val = "something"
        }
    }

    fmt.Println(n)
}

আউটপুট:

{[{key value} {href http://www.google.com}]}
{[{key value} {href something}]}

এটি Attributeস্লাইস বাউন্ড চেক ব্যয়ে একটি - সম্ভবত বড় - প্রকারের মানগুলির অনুলিপি তৈরি করা এড়ানো যায় । আপনার উদাহরণে, প্রকার Attributeতুলনামূলকভাবে ছোট, দুটি stringস্লাইস রেফারেন্স: একটি 64-বিট আর্কিটেকচার মেশিনে 2 * 3 * 8 = 48 বাইট।

আপনি সহজভাবে লিখতে পারেন:

for i := 0; i < len(n.Attr); i++ {
    if n.Attr[i].Key == "href" {
        n.Attr[i].Val = "something"
    }
}

তবে, একটি rangeধারা দ্বারা সমতুল্য ফলাফল পাওয়ার উপায় , যা একটি অনুলিপি তৈরি করে তবে স্লাইস বাউন্ডের চেকগুলি কমিয়ে দেয়, তা হ'ল:

for i, attr := range n.Attr {
    if attr.Key == "href" {
        n.Attr[i].Val = "something"
    }
}

2
এটা একটা দু: খের বিষয় যে value := &someMap[key]হবে কাজ না হলে someMapএকটি হলmap
warvariuc

আপনার প্রথম কোড স্নিপেটে পিটারসো এটিকে কিছু বরাদ্দ করার জন্য আপনার এট্রেয়ারকে ডিফেন্স করতে হবে না? অর্থাত্*attr.Val = "something"
হোমম বাহরানী

25

আমি আপনার শেষ পরামর্শটি মানিয়ে নেব এবং কেবলমাত্র পরিসীমাটির সূচি সংস্করণটি ব্যবহার করব।

for i := range n.Attr {
    if n.Attr[i].Key == "href" {
        n.Attr[i].Val = "something"
    }
}

এটা আমার কাছে সহজ মনে হয় উল্লেখ করতে n.Attr[i]উভয় লাইনে স্পষ্টভাবে পরীক্ষা Keyএবং লাইন যে সেট Val, বরং ব্যবহার না করে attrএক জন্য এবং n.Attr[i]অন্যের জন্য।


15

উদাহরণ স্বরূপ:

package main

import "fmt"

type Attribute struct {
        Key, Val string
}

type Node struct {
        Attr []*Attribute
}

func main() {
        n := Node{[]*Attribute{
                &Attribute{"foo", ""},
                &Attribute{"href", ""},
                &Attribute{"bar", ""},
        }}

        for _, attr := range n.Attr {
                if attr.Key == "href" {
                        attr.Val = "something"
                }
        }

        for _, v := range n.Attr {
                fmt.Printf("%#v\n", *v)
        }
}

খেলার মাঠ


আউটপুট

main.Attribute{Key:"foo", Val:""}
main.Attribute{Key:"href", Val:"something"}
main.Attribute{Key:"bar", Val:""}

বিকল্প পথ বা পন্থা:

package main

import "fmt"

type Attribute struct {
        Key, Val string
}

type Node struct {
        Attr []Attribute
}

func main() {
        n := Node{[]Attribute{
            {"foo", ""},
            {"href", ""},
            {"bar", ""},
        }}

        for i := range n.Attr {
                attr := &n.Attr[i]
                if attr.Key == "href" {
                        attr.Val = "something"
                }
        }

        for _, v := range n.Attr {
                fmt.Printf("%#v\n", v)
        }
}

খেলার মাঠ


আউটপুট:

main.Attribute{Key:"foo", Val:""}
main.Attribute{Key:"href", Val:"something"}
main.Attribute{Key:"bar", Val:""}

আমি ভেবেছিলাম এটি সুস্পষ্ট ছিল তবে আমি যে কাঠামো পেয়েছি তা পরিবর্তন করতে চাই না (তারা go.net/htmlপ্যাকেজটি থেকে এসেছে )
ডেনিস সাগুরেট

1
@ অডিস্ট্রয়: উপরের দ্বিতীয় পদ্ধতির প্রকারগুলি ("কাঠামোগুলি") অপ্টটি পরিবর্তন করে না
zzzz

হ্যাঁ, আমি জানি, তবে এটি আসলে কিছুই আনছে না। আমি এমন একটি ধারণা আশা করছিলাম যা আমি সম্ভবত মিস করতে পারি। আমি আপনারা আত্মবিশ্বাসী বোধ করেন যে এরপরে কোনও সহজ সমাধান নেই that
সাগুরেট

1
@ অডিস্ট্রয়: এটি কিছু এনে দেয় , এটি এখানে অনুলিপি করে না এবং পুরো অ্যাট্রিবিউটকে ফিরে দেয় না । এবং হ্যাঁ, আমি নিশ্চিত যে উপাদানটির ডাবল কপি (আর + ডাব্লু) আপডেট এড়াতে কোনও স্লাইস উপাদানটির ঠিকানা নেওয়া সর্বোত্তম সমাধান।
zzzz
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.