Why Doesn't "len()" Work With Structs?

1,372 views
Skip to first unread message

jlfo...@berkeley.edu

unread,
Oct 24, 2021, 2:11:37 PM10/24/21
to golang-nuts
I noticed that the len() function doesn't take a struct as an argument (see below).
This is a big surprise. Can someone shed some light on why this restriction exists?

Cordially,
Jon Forrest

----------
package main

import "fmt"

var s struct {
        i1      int
        i2      int
}

func main() {
       fmt.Printf("len(s) = %d\n", len(s)) // -- invalid argument s (type struct { i1 int; i2 int }) for len
}

Jan Mercl

unread,
Oct 24, 2021, 2:26:09 PM10/24/21
to jlfo...@berkeley.edu, golang-nuts
On Sun, Oct 24, 2021 at 8:11 PM jlfo...@berkeley.edu
<jlfo...@berkeley.edu> wrote:

> I noticed that the len() function doesn't take a struct as an argument (see below).
> This is a big surprise. Can someone shed some light on why this restriction exists?

What is the expected value of len() when applied to a struct?

Did you perhaps mean unsafe.Sizeof() instead?
https://pkg.go.dev/uns...@go1.17.2#Sizeof

Filip Dimitrovski

unread,
Oct 24, 2021, 2:29:58 PM10/24/21
to golang-nuts
len() works on indexed types - arrays, slices, maps, strings. It also works on buffered channels but we can consider that a sequence. I don't consider a struct a sequence. It's non-obvious what the behaviour would be. Both of these sound reasonable: len() should be the memory size of the struct like sizeof in C/C++ *or* it should be the sum of the lengths of its (sequence) members.

The first case is way too low-level for Go, because it belongs to an unsafe operation so that's an easy no, ... and it already exists as unsafe.Sizeof().

The second case (len being the sum of its members' lengths) would require recursive calls, and almost surely infinite cycles as we eventually get to pointers. 

jlfo...@berkeley.edu

unread,
Oct 24, 2021, 7:44:40 PM10/24/21
to golang-nuts
Thanks for the replies.

I had been trying to translate the trick from C into Go where you can find how many structures are in an initialized array of structures
by dividing the size of the array by the size of one structure. As I've learned, not only isn't this possible, because you can't get
the size of one structure, but also because it isn't necessary. Instead, using a slice of structures rather than an array, I can just do "len(structslice)".
That gives me what I need.

But, I still have some questions about the responses. First, I think the expected value of len(struct) should be its size, in bytes,
like with a string. Are there any examples of problems this would cause? I don't understand why this has to be
unsafe. (It could even be done at compile time). I also don't understand the comment about recursive calls. Since it's possible
to assign one structure to another I would think that the structure length is known. Since I'm new to Go I'm probably
not aware of the finer points that would make this not so.

Cordially,
Jon Forrest

Dan Kortschak

unread,
Oct 24, 2021, 8:14:44 PM10/24/21
to golan...@googlegroups.com
You can use len to determine the sizeof a struct.

https://play.golang.org/p/f0x8p_04lP1 ;)

jlfo...@berkeley.edu

unread,
Oct 24, 2021, 8:53:33 PM10/24/21
to golang-nuts
I'm now aware that that I could use

len(([unsafe.Sizeof(T{})][0]byte{}))

But this seems overly complicated. Plus, I don't see why
this is unsafe. Please advise.

Jon

Dan Kortschak

unread,
Oct 24, 2021, 11:17:10 PM10/24/21
to golan...@googlegroups.com
On Sun, 2021-10-24 at 17:53 -0700, jlfo...@berkeley.edu wrote:
> But this seems overly complicated.

Sorry. That was a joke. You asked why you can't use len(); you can, by
using it to it into create something that is indexable (and so a
possible parameter for len()).

> Plus, I don't see why this is unsafe. Please advise.

To get the size of a struct in bytes, you use the unsafe.Sizeof
operator (which is a compile time constant). This
https://github.com/golang/go/issues/5602 may help with knowing why that
is in unsafe.




burak serdar

unread,
Oct 25, 2021, 11:43:55 AM10/25/21
to jlfo...@berkeley.edu, golang-nuts
On Sun, Oct 24, 2021 at 6:54 PM jlfo...@berkeley.edu <jlfo...@berkeley.edu> wrote:
I'm now aware that that I could use

len(([unsafe.Sizeof(T{})][0]byte{}))

But this seems overly complicated. Plus, I don't see why
this is unsafe. Please advise.

Sizeof is unsafe because it returns the number of bytes of the underlying object, including the overhead such as padding or headers. For slices, it returns the size of the header, not the size of the underlying array. Sizeof also means you are probably bypassing the Go type system.
 
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/fa5a2544-314b-41e4-8686-2d55ac1ecf69n%40googlegroups.com.

burak serdar

unread,
Oct 25, 2021, 11:43:55 AM10/25/21
to jlfo...@berkeley.edu, golang-nuts
On Sun, Oct 24, 2021 at 12:12 PM jlfo...@berkeley.edu <jlfo...@berkeley.edu> wrote:
I noticed that the len() function doesn't take a struct as an argument (see below).
This is a big surprise. Can someone shed some light on why this restriction exists?

len() gives the number of elements in an object, not the size of the object. Maybe unsafe.Sizeof is what you are looking for: 

x:=[]int{1,2}
fmt.Println(len(x),unsafe.Sizeof(x))

Output: 2 24



Cordially,
Jon Forrest

----------
package main

import "fmt"

var s struct {
        i1      int
        i2      int
}

func main() {
       fmt.Printf("len(s) = %d\n", len(s)) // -- invalid argument s (type struct { i1 int; i2 int }) for len
}

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

jake...@gmail.com

unread,
Oct 25, 2021, 12:00:52 PM10/25/21
to golang-nuts
On Sunday, October 24, 2021 at 7:44:40 PM UTC-4 jlfo...@berkeley.edu wrote:
Thanks for the replies.

I had been trying to translate the trick from C into Go where you can find how many structures are in an initialized array of structures
by dividing the size of the array by the size of one structure. As I've learned, not only isn't this possible, because you can't get
the size of one structure, but also because it isn't necessary. Instead, using a slice of structures rather than an array, I can just do "len(structslice)".
That gives me what I need.

You don't even need to use "a slice of structures rather than an array", since len() works just fine with arrays. See https://play.golang.org/p/I71I-5DlGKH.

But it is unclear why you want to get the number of elements in an array. In Go, if you have an array, you always know the size. Perhaps an example would help?

You may be used to using arrays in other languages. But in Go arrays are rarely used. In the vast majority of cases slices are preferred. This is, in part, because arrays in Go are values. When you assign one array to another, or when you pass an array to a function, the entire contents are copied. As you can imagine, this can be quite expensive. That is not to say that arrays should never be used in Go, but a slice should be your default go to, unless you have a real need for the value (copy ) semantics of an array, or have another compelling reason.

Ian Lance Taylor

unread,
Oct 25, 2021, 5:48:50 PM10/25/21
to jlfo...@berkeley.edu, golang-nuts
On Sun, Oct 24, 2021 at 4:45 PM jlfo...@berkeley.edu
<jlfo...@berkeley.edu> wrote:
>
> But, I still have some questions about the responses. First, I think the expected value of len(struct) should be its size, in bytes,
> like with a string. Are there any examples of problems this would cause?

I believe that that would be surprising. For example,
unsafe.Sizeof("") == 16 (on a 64-bit platform) but len("") == 0. len
always returns the number of elements contained in some aggregate
type, not the size of a value of that type. So if we supported len on
a struct type, I think the most natural value to return would be the
number of fields, not the total size of the struct. But of course
that isn't very useful in practice, so we simply don't support len on
a struct type.

> I don't understand why this has to be
> unsafe. (It could even be done at compile time). I also don't understand the comment about recursive calls. Since it's possible
> to assign one structure to another I would think that the structure length is known. Since I'm new to Go I'm probably
> not aware of the finer points that would make this not so.

The size of a struct type is indeed known at compile time, and
unsafe.Sizeof applied to a struct type returns a constant that is the
size of the struct. You're right in that this does not really have to
be in unsafe (and you can get the same value using the reflect package
without using unsafe, although the result will be not technically be a
constant--it will always be the same value, but you can't use it to
set the size of an array). unsafe.Sizeof is in unsafe mainly for
historical reasons and because there wasn't anywhere else natural to
put it.

Ian

Rob Pike

unread,
Oct 25, 2021, 6:35:52 PM10/25/21
to Ian Lance Taylor, jlfo...@berkeley.edu, golang-nuts
See also https://github.com/golang/go/issues/29982. It gets more
interesting towards the bottom, but the proposal is on hold.

Be nice to release it again though. I do favor it.

-rob
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAOyqgcUNXB0C2f4ReqdkAbDoLsgUM87FA8Ko%2BkvZ0BJtG0tCRA%40mail.gmail.com.

Brian Candler

unread,
Oct 26, 2021, 3:28:04 AM10/26/21
to golang-nuts
On Monday, 25 October 2021 at 22:48:50 UTC+1 Ian Lance Taylor wrote:
unsafe.Sizeof is in unsafe mainly for
historical reasons and because there wasn't anywhere else natural to
put it.

If you *need* to know the size-in-bytes of any Go internal data structure, then you are almost certainly doing something unsafe :-) 

Adhithi Pai B

unread,
Oct 29, 2021, 1:04:50 PM10/29/21
to golang-nuts
package main

import (
     "fmt"
)
type Address struct {
        Doorno      int64

}

type studentdetails struct {          
        Name     string
        RollNo         int
        AddressList    Address
}
type class struct {                   
        //ueCtx  gnodeb_proxy_util.RanUeContext
        Multiplestudents map[string]*studentdetails
        //config *GNBProxyConfig
}
func main() {
    var s1 string="A"
    classA:=new(class)
    classA.Multiplestudents=make(map[string]*studentdetails)
    classA.Multiplestudents[s1]={Name:"s1",RollNo:10, AddressList: Address{Doorno:10}}        
    fmt.Println(classA.MultipleUE[s1])

Kurtis Rader

unread,
Oct 29, 2021, 5:07:34 PM10/29/21
to Adhithi Pai B, golang-nuts
You didn't tell us what the problem is or the version of Go you're using. In any event, your code has a couple of problems. This line

classA.Multiplestudents[s1]={Name:"s1",RollNo:10, AddressList: Address{Doorno:10}}

should be

classA.Multiplestudents[s1]= &studentdetails{Name:"s1",RollNo:10, AddressList: Address{Doorno:10}}

And your type class has no "MultipleUE" member. Presumably you meant "classA.Multiplestudents[s1]".

On Fri, Oct 29, 2021 at 10:04 AM Adhithi Pai B <paiad...@gmail.com> wrote:
package main

import (
     "fmt"
)
type Address struct {
        Doorno      int64

}

type studentdetails struct {          
        Name     string
        RollNo         int
        AddressList    Address
}
type class struct {                   
        //ueCtx  gnodeb_proxy_util.RanUeContext
        Multiplestudents map[string]*studentdetails
        //config *GNBProxyConfig
}
func main() {
    var s1 string="A"
    classA:=new(class)
    classA.Multiplestudents=make(map[string]*studentdetails)
    classA.Multiplestudents[s1]={Name:"s1",RollNo:10, AddressList: Address{Doorno:10}}        
    fmt.Println(classA.MultipleUE[s1])

}

--
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

Adhithi Pai B

unread,
Oct 30, 2021, 1:21:45 AM10/30/21
to Kurtis Rader, golang-nuts
Thank you! 
Reply all
Reply to author
Forward
0 new messages