[] স্ট্রিংকে [] ইন্টারফেসে রূপান্তর করা যায় না {}


96

আমি কিছু কোড লিখছি, এবং আমার এটি আর্গুমেন্টগুলি ধরা এবং এটিগুলি পাস করার জন্য প্রয়োজন fmt.Println
(আমি এর ডিফল্ট আচরণ চাই, স্পেস দিয়ে আলাদা করে যুক্তি লিখতে এবং একটি নতুন লাইন অনুসরণ করি)। তবে এটা লাগে []interface {}কিন্তু flag.Args()একটি ফেরৎ []string
কোডের উদাহরণ এখানে:

package main

import (
    "fmt"
    "flag"
)

func main() {
    flag.Parse()
    fmt.Println(flag.Args()...)
}

এটি নিম্নলিখিত ত্রুটি প্রদান করে:

./example.go:10: cannot use args (type []string) as type []interface {} in function argument

এটি কি বাগ? কোন অ্যারে fmt.Printlnনেওয়া উচিত ? যাইহোক, আমি এটি করার চেষ্টাও করেছি:

var args = []interface{}(flag.Args())

তবে আমি নিম্নলিখিত ত্রুটি পেয়েছি:

cannot convert flag.Args() (type []string) to type []interface {}

এটির মতো কাজ করার কোনও "গো" উপায় আছে?


4
আমি একটি সাধারণ উদাহরণ ( go run test.go some test flags) দিয়ে জগাখিচুড়ি করছিলাম , এবং যখন flags.Args()...ঠিক flag.Args()( পরিবর্তিত আউটপুটটি [some test flags]নিউলাইন দ্বারা অনুসরণ করা হয়েছে; প্রকৃত পতাকাগুলি নিবন্ধকরণের সাথেও কাজ করবে বলে মনে হচ্ছে) কাজ করে যাচ্ছিল seemed কেন বোঝার ভান করবেন না, এবং স্টিফেনের উত্তর যাইহোক
উপায়গুলি

উত্তর:


116

এটি একটি বাগ না। fmt.Println()এক []interface{}প্রকারের দরকার তার অর্থ, এটি অবশ্যই interface{}মানগুলির একটি টুকরা হতে হবে এবং "কোনও স্লাইস" নয়। স্লাইস রূপান্তর করতে, আপনাকে প্রতিটি উপাদান লুপ করে কপি করতে হবে।

old := flag.Args()
new := make([]interface{}, len(old))
for i, v := range old {
    new[i] = v
}
fmt.Println(new...)

আপনি কোনও স্লাইস ব্যবহার করতে পারবেন না তার কারণ হ'ল a []stringএবং a এর মধ্যে রূপান্তরকরণের []interface{}জন্য মেমরির বিন্যাসটি পরিবর্তন করা দরকার এবং ও (এন) সময়ে ঘটে। কোনও প্রকারকে একটিতে রূপান্তর করতে interface{}ও (1) সময়ের প্রয়োজন। যদি তারা এটিকে লুপটির জন্য অপ্রয়োজনীয় করে তোলে তবে সংকলকটিকে এখনও এটি প্রবেশ করানো দরকার।


4
যাইহোক, আমি এই লিঙ্কটি গোলং-বাদামগুলিতে পেয়েছি
ডটকম /

4
হ্যাঁ, প্রতিটি পুনরাবৃত্তির জন্য ও (1) সময় প্রয়োজন এবং লুপের জন্য ও (এন) সময় প্রয়োজন। এটাই আমি বলেছিলাম। ফাংশনটি প্রাপ্তির ক্ষেত্রে []stringএটি প্রত্যাশা করে a interface{}। একটি interface{}থেকে আলাদা মেমরি লেআউট থাকে stringযাতে প্রতিটি উপাদানকে রূপান্তরিত করা দরকার তা হ'ল সমস্যা।
স্টিফেন ওয়েইনবার্গ

4
@ কার্লরহ: না, ধরুন Printlnফাংশনটি স্লাইসটি সংশোধন করে এবং কিছু উপাদান সেট করে (এটি না, তবে ধরুন এটি করা হয়)। তারপরে এটি কোনও interface{}স্লাইসে রাখতে পারে, যা কেবল stringএস only আপনি যা চান তা জাভা জেনেরিক্স ওয়াইল্ডকার্ডের মতো কিছু Slice<? extends []interface{}>তবে গোতে এটি বিদ্যমান নেই doesn't
newacct

4
সংযোজন যাদু। এটি অন্তর্নির্মিত এবং ভাষা দ্বারা বিশেষভাবে চিকিত্সা করা হয়। অন্যান্য উদাহরণ অন্তর্ভুক্ত new(), len()এবং copy()golang.org/ref/spec# Append___copying_slices
স্টিফেন ওয়েইনবার্গ

4
আজ আমি শিখলাম 'নতুন' কোনও রিজার্ভ কীওয়ার্ড নয়! না হয় না!
শ্রীধর

11

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

package main

import (
    "fmt"
    "flag"
    "strings"
)

func main() {
    flag.Parse()
    s := strings.Join(flag.Args(), " ")
    fmt.Println(s)
}

11

এই ক্ষেত্রে, একটি ধরণের রূপান্তর অপ্রয়োজনীয়। কেবল flag.Args()মানটি পাস করুন fmt.Println


প্রশ্ন:

[] স্ট্রিংকে [] ইন্টারফেসে রূপান্তর করা যায় না {}

আমি কিছু কোড লিখছি, এবং আমার এটি আর্গুমেন্টগুলি ধরতে এবং এফএমটি.প্রিন্টলনের মাধ্যমে পাস করার প্রয়োজন (আমি এর ডিফল্ট আচরণটি চাই, স্পেস দিয়ে আলাদা করে যুক্তি লিখতে এবং একটি নতুন লাইন অনুসরণ করি)।

কোডের উদাহরণ এখানে:

package main

import (
    "fmt"
    "flag"
)

func main() {
    flag.Parse()
    fmt.Println(flag.Args()...)
}

প্যাকেজ পতাকা

import "flag"

ফানক আরগস

func Args() []string

Args পতাকাবিহীন কমান্ড-লাইন আর্গুমেন্ট প্রদান করে।


প্যাকেজ এফএমটি

import "fmt"

ফানক মুদ্রণ

func Println(a ...interface{}) (n int, err error)

Printlnএর অপারেশনগুলির জন্য ডিফল্ট ফর্ম্যাটগুলি ব্যবহার করে ফর্ম্যাটগুলি এবং স্ট্যান্ডার্ড আউটপুটে লেখেন। অপারেশনগুলির মধ্যে সর্বদা স্পেস যুক্ত হয় এবং একটি নতুন লাইন যুক্ত হয়। এটি লিখিত বাইটের সংখ্যা এবং যে কোনও লিখনের ত্রুটির মুখোমুখি হয় returns


এই ক্ষেত্রে, একটি ধরণের রূপান্তর অপ্রয়োজনীয়। কেবলমাত্র flag.Args()মানটি পাস করুন fmt.Println, যা মানটিকে টাইপ হিসাবে ব্যাখ্যা করতে প্রতিবিম্ব ব্যবহার করে []string। প্যাকেজ reflectরান-টাইম রিফ্লেকশন প্রয়োগ করে, একটি প্রোগ্রামকে স্বেচ্ছাসেবী প্রকারের সাথে জিনিসগুলিতে হস্তক্ষেপ করার অনুমতি দেয়। উদাহরণ স্বরূপ,

args.go:

package main

import (
    "flag"
    "fmt"
)

func main() {
    flag.Parse()
    fmt.Println(flag.Args())
}

আউটপুট:

$ go build args.go
$ ./args arg0 arg1
[arg0 arg1]
$ 

যদি আমি বন্ধনীগুলি বাদ দিতে চাইতাম তবে রূপান্তরটি কি অপ্রয়োজনীয় হবে?
ক্রুজ

1

গো-তে, একটি ফাংশন কেবলমাত্র ফাংশন সংজ্ঞাতে পরামিতি তালিকায় নির্দিষ্ট ধরণের যুক্তি গ্রহণ করতে পারে। বৈকল্পিক প্যারামিটার ভাষার বৈশিষ্ট্যটি কিছুটা জটিল করে তোলে তবে এটি যথাযথভাবে সংজ্ঞায়িত নিয়ম অনুসরণ করে।

ফাংশনের স্বাক্ষরটি fmt.Printlnহ'ল:

func Println(a ...interface{}) (n int, err error)

প্রতি ভাষা specifiction ,

একটি ফাংশন স্বাক্ষরের চূড়ান্ত ইনকামিং প্যারামিটারটির একটি প্রিফিক্সযুক্ত প্রাইস থাকতে পারে .... এই জাতীয় পরামিতি সহ একটি ফাংশনটিকে ভেরিয়াদিক বলা হয় এবং সেই পরামিতির শূন্য বা আরও বেশি যুক্তি যুক্ত করা যেতে পারে।

এর অর্থ আপনি প্রকারের Printlnআর্গুমেন্টের একটি তালিকা পাস করতে পারেন interface{}। যেহেতু সমস্ত ধরণের খালি ইন্টারফেস বাস্তবায়িত হয়, আপনি কোনও প্রকারের আর্গুমেন্টের একটি তালিকা পাস করতে পারেন Println(1, "one", true), উদাহরণস্বরূপ, ত্রুটি ছাড়াই আপনি কল করতে সক্ষম হন । দেখুন "এ ... পরামিতি আর্গুমেন্ট পাসিং" বিভাগে ভাষা স্পেসিফিকেশন-এর:

পাস করা মান হ'ল একটি নতুন ধরণের টুকরো [] টি একটি নতুন অন্তর্নিহিত অ্যারে সহ যার ধারাবাহিক উপাদানগুলি আসল যুক্তি, যা সকলকে অবশ্যই টিতে নির্ধারিত হতে হবে T

যে অংশটি আপনাকে সমস্যা দিচ্ছে তা নির্দিষ্টকরণের ঠিক পরে:

যদি চূড়ান্ত যুক্তি একটি স্লাইস ধরণের [] টি তে নির্ধারিত হয় তবে এটি আর্গুমেন্টটি অনুসরণ করা হয় ... টি প্যারামিটারের মান হিসাবে অপরিবর্তিত হতে পারে .... এই ক্ষেত্রে কোনও নতুন স্লাইস তৈরি করা হয় না।

flag.Args()টাইপ হয় []string। যেহেতু TPrintlnহলinterface{} , []Tহয় []interface{}। সুতরাং প্রশ্নটি নেমে আসে কিনা একটি স্ট্রিং স্লাইস মান ইন্টারফেসের স্লাইস টাইপের একটি পরিবর্তনশীলকে নির্ধারিত হয়। আপনি কোনও অ্যাসাইনমেন্ট চেষ্টা করে আপনার গো কোডে সহজেই এটি পরীক্ষা করতে পারেন, উদাহরণস্বরূপ:

s := []string{}
var i []interface{}
i = s

আপনি যদি এই জাতীয় কোনও কার্যকারিতা চেষ্টা করেন, সংকলক এই ত্রুটি বার্তাকে আউটপুট দেবে:

cannot use s (type []string) as type []interface {} in assignment

এবং এ কারণেই আপনি স্ট্রল স্লাইসের পরে উপবৃত্তিকে যুক্তি হিসাবে ব্যবহার করতে পারবেন না fmt.Println। এটি কোনও বাগ নয়, এটি ইচ্ছাকৃতভাবে কাজ করছে।

সেখানে উপায়ে আপনি মুদ্রণ করতে পারেন এখনও প্রচুর আছে flag.Args()সঙ্গে Printlnযেমন

fmt.Println(flag.Args())

(যা [elem0 elem1 ...]প্রতি হিসাবে আউটপুট হবে এফএমটি প্যাকেজ নথি )

বা

fmt.Println(strings.Join(flag.Args(), ` `)

(যা স্ট্রিং স্লাইস উপাদানগুলিকে আউটপুট দেবে, প্রত্যেকে একটি একক স্থান দ্বারা পৃথক করা হবে) উদাহরণস্বরূপ স্ট্রিং বিভাজক সহ স্ট্রিং প্যাকেজে জোড় ফাংশনটি ব্যবহার করে


0

আমি মনে করি এটি প্রতিবিম্ব ব্যবহার করে সম্ভব, তবে আমি জানি না এটির কোনও ভাল সমাধান কিনা

package main

import (
    "fmt"
    "reflect"
    "strings"
)

type User struct {
    Name string
    Age  byte
}

func main() {
    flag.Parse()
    fmt.Println(String(flag.Args()))
    fmt.Println(String([]string{"hello", "world"}))
    fmt.Println(String([]int{1, 2, 3, 4, 5, 6}))
    u1, u2 := User{Name: "John", Age: 30},
        User{Name: "Not John", Age: 20}
    fmt.Println(String([]User{u1, u2}))
}

func String(v interface{}) string {
    val := reflect.ValueOf(v)
    if val.Kind() == reflect.Array || val.Kind() == reflect.Slice {
        l := val.Len()
        if l == 0 {
            return ""
        }
        if l == 1 {
            return fmt.Sprint(val.Index(0))
        }
        sb := strings.Builder{}
        sb.Grow(l * 4)
        sb.WriteString(fmt.Sprint(val.Index(0)))
        for i := 1; i < l; i++ {
            sb.WriteString(",")
            sb.WriteString(fmt.Sprint(val.Index(i)))
        }
        return sb.String()
    }

    return fmt.Sprintln(v)
}

আউটপুট:

$ go run .\main.go arg1 arg2
arg1,arg2
hello,world
1,2,3,4,5,6
{John 30},{Not John 20}

-1

fmt.Printlnবৈকল্পিক পরামিতি নেয়

ফানক প্রিন্টলন (একটি ... ইন্টারফেস {}) (এনটি, ভুল ত্রুটি)

flag.Args()রূপান্তর না করে মুদ্রণ করা সম্ভব[]interface{}

func main() {
    flag.Parse()
    fmt.Println(flag.Args())
}

4
fmt.Printlnএর স্বাক্ষর 6 বছরেরও বেশি সময় পরিবর্তিত হয়নি (এবং এটি ছিল কেবল একটি প্যাকেজ পরিবর্তন error)। এমনকি যদি এটা ছিল, বৈশিষ্ট পরিষ্কারভাবে, তারপর টাইপ করতে মধ্যে চ পি ধরণ সমতূল্য ধরনের একটি চূড়ান্ত প্যারামিটার পি ... টি সঙ্গে variadic [] T.` তাই এটা কোন ব্যাপার না would বলেছেন `। fmt.Println(flags.Args()...)এখনও কাজ করে না (আপনি স্লাইস সম্প্রসারণ মিস করছেন), fmt.Println(flags.Args())সর্বদা কাজ করে।
মার্ক

আপনি এই তথ্যটি কীভাবে পেলেন যে fmt. মুদ্রণযন্ত্রের স্বাক্ষর 6 বছরেরও বেশি সময় পরিবর্তিত হয়নি? আপনি কি সোর্স কোডটি পরীক্ষা করেছেন?
শাহরিয়ার

হ্যাঁ: github.com/golang/go/blame/release-branch.go1.10/src/fmt/... (1.10 শাখা দিকে)
মার্ক

অপটিতে মন্তব্যটি পরামর্শ দেয় যে flag.Args()পুরোপুরি যুক্তি হিসাবে সেই সময়টিকে কাজে লাগানো fmt.Printlnউচিত। (বিস্ময়ের বিষয় হবে যদি এটি সেই সময়ে না হয়)
পাতায় bebop

তাহলে? যদি কোনও মন্তব্য উপস্থিত থাকে, তার মানে আমার উত্তরটি ভোট দেওয়া উচিত?
শাহরিয়ার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.