<!-- title The Go Programming Language Specification -->
-<!-- subtitle Version of August 31, 2011 -->
+<!-- subtitle Version of September 29, 2011 -->
<!--
TODO
where <code>T</code> is the <a href="#Slice_types">element type</a> of
<code>S</code> and the respective
<a href="#Passing_arguments_to_..._parameters">parameter passing rules</a> apply.
+As a special case, <code>append</code> also accepts a first argument
+assignable to type <code>[]byte</code> with a second argument of
+string type followed by <code>...</code>. This form appends the
+bytes of the string.
</p>
<pre class="grammar">
If the capacity of <code>s</code> is not large enough to fit the additional
values, <code>append</code> allocates a new, sufficiently large slice that fits
both the existing slice elements and the additional values. Thus, the returned
-slice may refer to a different underlying array.
+slice may refer to a different underlying array.
</p>
<pre>
var t []interface{}
t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"}
+
+var b []byte
+b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
</pre>
<p>
"func @\"\".concatstring ()\n"
"func @\"\".append ()\n"
"func @\"\".appendslice (typ *uint8, x any, y []any) any\n"
+ "func @\"\".appendstr (typ *uint8, x []uint8, y string) []uint8\n"
"func @\"\".cmpstring (? string, ? string) int\n"
"func @\"\".slicestring (? string, ? int, ? int) string\n"
"func @\"\".slicestring1 (? string, ? int) string\n"
// filled in by compiler: Type*, int n, Slice, ...
func append()
func appendslice(typ *byte, x any, y []any) any
+func appendstr(typ *byte, x []byte, y string) []byte
func cmpstring(string, string) int
func slicestring(string, int, int) string
yyerror("too many arguments to append");
goto error;
}
+ if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) {
+ defaultlit(&args->next->n, types[TSTRING]);
+ goto ret;
+ }
args->next->n = assignconv(args->next->n, t->orig, "append");
goto ret;
}
goto error;
defaultlit(&n->left, T);
defaultlit(&n->right, T);
-
+
// copy([]byte, string)
if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
if(n->left->type->type == types[TUINT8])
yyerror("arguments to copy have different element types: %lT and string", n->left->type);
goto error;
}
-
+
if(!isslice(n->left->type) || !isslice(n->right->type)) {
if(!isslice(n->left->type) && !isslice(n->right->type))
yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
paramoutheap(Node *fn)
{
NodeList *l;
-
+
for(l=fn->dcl; l; l=l->next) {
switch(l->n->class) {
case PPARAMOUT|PHEAP:
case OLEN:
case OCAP:
walkexpr(&n->left, init);
-
+
// replace len(*[10]int) with 10.
// delayed until now to preserve side effects.
t = n->left->type;
n->typecheck = 1;
}
goto ret;
-
+
case OLSH:
case ORSH:
case OAND:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
-
+
case OANDAND:
case OOROR:
walkexpr(&n->left, init);
walkexprlistsafe(n->list, init);
walkexpr(&r, init);
l = n->list->n;
-
+
// all the really hard stuff - explicit function calls and so on -
// is gone, but map assignments remain.
// if there are map assignments here, assign via
if(n->op == ODOTTYPE2)
*p++ = '2';
*p = '\0';
-
+
fn = syslook(buf, 1);
ll = list1(typename(n->type));
ll = list(ll, n->left);
else
*p++ = 'I';
*p = '\0';
-
+
fn = syslook(buf, 1);
ll = nil;
if(!isinter(n->left->type))
}
if(v1 >= 0 && v2 >= 0 && v1 > v2)
yyerror("inverted slice range");
-
+
if(n->op == OSLICEARR)
goto slicearray;
l,
nodintconst(t->type->width));
}
- n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
+ n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
goto ret;
slicearray:
l);
}
goto ret;
-
+
case OAPPEND:
- if(n->isddd)
- n = appendslice(n, init);
+ if(n->isddd) {
+ if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING))
+ n = mkcall("appendstr", n->type, init, typename(n->type), n->list->n, n->list->next->n);
+ else
+ n = appendslice(n, init);
+ }
else
n = append(n, init);
goto ret;
{
Node *a, *n;
Type *tslice;
-
+
tslice = typ(TARRAY);
tslice->type = l->type->type;
tslice->bound = -1;
if(lr)
r = lr->n;
nn = nil;
-
+
// f(g()) where g has multiple return values
if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
// optimization - can do block copy
nn = list1(convas(nod(OAS, a, r), init));
goto ret;
}
-
+
// conversions involved.
// copy into temporaries.
alist = nil;
n->left->left, n->left->right, n->right);
goto out;
}
-
+
if(eqtype(lt, rt))
goto out;
-
+
n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init);
{
NodeList *nn;
int32 lno;
-
+
lno = lineno;
lineno = curfn->lineno;
nn = paramstoheap(getthis(curfn->type), 0);
Node *r, *cat, *typstr;
NodeList *in, *args;
int i, count;
-
+
count = 0;
for(r=n; r->op == OADDSTR; r=r->left)
count++; // r->right
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
-
+
return r;
}
appendslice(Node *n, NodeList **init)
{
Node *f;
-
+
f = syslook("appendslice", 1);
argtype(f, n->type);
argtype(f, n->type->type);
// s := src
// const argc = len(args) - 1
// if cap(s) - len(s) < argc {
-// s = growslice(s, argc)
+// s = growslice(s, argc)
// }
// n := len(s)
// s = s[:n+argc]
ns = temp(nsrc->type);
l = list(l, nod(OAS, ns, nsrc)); // s = src
- na = nodintconst(argc); // const argc
- nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
+ na = nodintconst(argc); // const argc
+ nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
- fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
- argtype(fn, ns->type->type); // 1 old []any
- argtype(fn, ns->type->type); // 2 ret []any
+ fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
+ argtype(fn, ns->type->type); // 1 old []any
+ argtype(fn, ns->type->type); // 2 ret []any
nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
typename(ns->type),
l = list(l, nx);
nn = temp(types[TINT]);
- l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
+ l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
- nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
+ nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
- for (a = n->list->next; a != nil; a = a->next) {
- nx = nod(OINDEX, ns, nn); // s[n] ...
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
+ for (a = n->list->next; a != nil; a = a->next) {
+ nx = nod(OINDEX, ns, nn); // s[n] ...
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
if (a->next != nil)
l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
}
static void makeslice1(SliceType*, int32, int32, Slice*);
static void growslice1(SliceType*, Slice, int32, Slice *);
-static void appendslice1(SliceType*, Slice, Slice, Slice*);
void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
// see also unsafe·NewArray
if(debug) {
runtime·printf("makeslice(%S, %D, %D); ret=",
*t->string, len, cap);
- runtime·printslice(ret);
+ runtime·printslice(ret);
}
}
static void
makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
-{
+{
uintptr size;
size = cap*t->elem->size;
void
runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
{
- appendslice1(t, x, y, &ret);
+ int32 m;
+ uintptr w;
+
+ m = x.len+y.len;
+
+ if(m < x.len)
+ runtime·throw("append: slice overflow");
+
+ if(m > x.cap)
+ growslice1(t, x, m, &ret);
+ else
+ ret = x;
+
+ w = t->elem->size;
+ runtime·memmove(ret.array + ret.len*w, y.array, y.len*w);
+ ret.len += y.len;
+ FLUSH(&ret);
}
-static void
-appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
+
+// appendstr([]byte, string) []byte
+void
+runtime·appendstr(SliceType *t, Slice x, String y, Slice ret)
{
int32 m;
- uintptr w;
m = x.len+y.len;
runtime·throw("append: slice overflow");
if(m > x.cap)
- growslice1(t, x, m, ret);
+ growslice1(t, x, m, &ret);
else
- *ret = x;
+ ret = x;
- w = t->elem->size;
- runtime·memmove(ret->array + ret->len*w, y.array, y.len*w);
- ret->len += y.len;
+ runtime·memmove(ret.array + ret.len, y.str, y.len);
+ ret.len += y.len;
+ FLUSH(&ret);
}
+
// growslice(type *Type, x, []T, n int64) []T
void
runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
if(debug) {
runtime·printf("growslice(%S,", *t->string);
- runtime·printslice(old);
+ runtime·printslice(old);
runtime·printf(", new cap=%D) =", cap);
- runtime·printslice(ret);
+ runtime·printslice(ret);
}
}
ret = 0;
goto out;
}
-
+
ret = fm.len;
if(to.len < ret)
ret = to.len;
-
+
runtime·memmove(to.array, fm.str, ret);
out:
{"byte i", append([]byte{0, 1, 2}, []byte{3}...), []byte{0, 1, 2, 3}},
{"byte j", append([]byte{0, 1, 2}, []byte{3, 4, 5}...), []byte{0, 1, 2, 3, 4, 5}},
+ {"bytestr a", append([]byte{}, "0"...), []byte("0")},
+ {"bytestr b", append([]byte{}, "0123"...), []byte("0123")},
+
+ {"bytestr c", append([]byte("012"), "3"...), []byte("0123")},
+ {"bytestr d", append([]byte("012"), "345"...), []byte("012345")},
{"int16 a", append([]int16{}), []int16{}},
{"int16 b", append([]int16{}, 0), []int16{0}},