mirror of
https://github.com/golang/go
synced 2024-11-21 17:34:40 -07:00
allow direct conversion between string and named []byte, []rune
The allowed conversions before and after are: type Tstring string type Tbyte []byte type Trune []rune string <-> string // ok string <-> []byte // ok string <-> []rune // ok string <-> Tstring // ok string <-> Tbyte // was illegal, now ok string <-> Trune // was illegal, now ok Tstring <-> string // ok Tstring <-> []byte // ok Tstring <-> []rune // ok Tstring <-> Tstring // ok Tstring <-> Tbyte // was illegal, now ok Tstring <-> Trune // was illegal, now ok Update spec, compiler, tests. Use in a few packages. We agreed on this a few months ago but never implemented it. Fixes #1707. R=golang-dev, gri, r CC=golang-dev https://golang.org/cl/5421057
This commit is contained in:
parent
c69d6345da
commit
6e3e380923
@ -1,5 +1,5 @@
|
||||
<!-- title The Go Programming Language Specification -->
|
||||
<!-- subtitle Version of November 14, 2011 -->
|
||||
<!-- subtitle Version of November 22, 2011 -->
|
||||
|
||||
<!--
|
||||
TODO
|
||||
@ -3346,42 +3346,50 @@ MyString(0x65e5) // "\u65e5" == "日" == "\xe6\x97\xa5"
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Converting a value of type <code>[]byte</code> to a string type yields
|
||||
Converting a slice of bytes to a string type yields
|
||||
a string whose successive bytes are the elements of the slice. If
|
||||
the slice value is <code>nil</code>, the result is the empty string.
|
||||
|
||||
<pre>
|
||||
string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
|
||||
|
||||
type MyBytes []byte
|
||||
string(MyBytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Converting a value of type <code>[]rune</code> to a string type yields
|
||||
Converting a slice of runes to a string type yields
|
||||
a string that is the concatenation of the individual rune values
|
||||
converted to strings. If the slice value is <code>nil</code>, the
|
||||
result is the empty string.
|
||||
|
||||
<pre>
|
||||
string([]rune{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"
|
||||
|
||||
type MyRunes []rune
|
||||
string(MyRunes{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Converting a value of a string type to <code>[]byte</code> (or <code>[]uint8</code>)
|
||||
Converting a value of a string type to a slice of bytes type
|
||||
yields a slice whose successive elements are the bytes of the string.
|
||||
If the string is empty, the result is <code>[]byte(nil)</code>.
|
||||
|
||||
<pre>
|
||||
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
|
||||
MyBytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Converting a value of a string type to <code>[]rune</code> yields a
|
||||
slice containing the individual Unicode code points of the string.
|
||||
Converting a value of a string type to a slice of runes type
|
||||
yields a slice containing the individual Unicode code points of the string.
|
||||
If the string is empty, the result is <code>[]rune(nil)</code>.
|
||||
<pre>
|
||||
[]rune(MyString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4}
|
||||
MyRunes("白鵬翔") // []rune{0x767d, 0x9d6c, 0x7fd4}
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
@ -1177,19 +1177,19 @@ convertop(Type *src, Type *dst, char **why)
|
||||
if(isint[src->etype] && dst->etype == TSTRING)
|
||||
return ORUNESTR;
|
||||
|
||||
if(isslice(src) && src->sym == nil && dst->etype == TSTRING) {
|
||||
if(eqtype(src->type, bytetype))
|
||||
if(isslice(src) && dst->etype == TSTRING) {
|
||||
if(src->type->etype == bytetype->etype)
|
||||
return OARRAYBYTESTR;
|
||||
if(eqtype(src->type, runetype))
|
||||
if(src->type->etype == runetype->etype)
|
||||
return OARRAYRUNESTR;
|
||||
}
|
||||
|
||||
// 7. src is a string and dst is []byte or []rune.
|
||||
// String to slice.
|
||||
if(src->etype == TSTRING && isslice(dst) && dst->sym == nil) {
|
||||
if(eqtype(dst->type, bytetype))
|
||||
if(src->etype == TSTRING && isslice(dst)) {
|
||||
if(dst->type->etype == bytetype->etype)
|
||||
return OSTRARRAYBYTE;
|
||||
if(eqtype(dst->type, runetype))
|
||||
if(dst->type->etype == runetype->etype)
|
||||
return OSTRARRAYRUNE;
|
||||
}
|
||||
|
||||
|
@ -29,71 +29,69 @@ const testInput = `
|
||||
</body><!-- missing final newline -->`
|
||||
|
||||
var rawTokens = []Token{
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
|
||||
),
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
|
||||
CharData([]byte("World <>'\" 白鵬翔")),
|
||||
CharData("World <>'\" 白鵬翔"),
|
||||
EndElement{Name{"", "hello"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"", "goodbye"}, []Attr{}},
|
||||
EndElement{Name{"", "goodbye"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"", "inner"}, []Attr{}},
|
||||
EndElement{Name{"", "inner"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
EndElement{Name{"", "outer"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"tag", "name"}, []Attr{}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData([]byte("Some text here.")),
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
CharData("Some text here."),
|
||||
CharData("\n "),
|
||||
EndElement{Name{"tag", "name"}},
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
EndElement{Name{"", "body"}},
|
||||
Comment([]byte(" missing final newline ")),
|
||||
Comment(" missing final newline "),
|
||||
}
|
||||
|
||||
var cookedTokens = []Token{
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
|
||||
),
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
|
||||
CharData([]byte("World <>'\" 白鵬翔")),
|
||||
CharData("World <>'\" 白鵬翔"),
|
||||
EndElement{Name{"ns2", "hello"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"ns2", "goodbye"}, []Attr{}},
|
||||
EndElement{Name{"ns2", "goodbye"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"ns2", "inner"}, []Attr{}},
|
||||
EndElement{Name{"ns2", "inner"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
EndElement{Name{"ns2", "outer"}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
StartElement{Name{"ns3", "name"}, []Attr{}},
|
||||
CharData([]byte("\n ")),
|
||||
CharData([]byte("Some text here.")),
|
||||
CharData([]byte("\n ")),
|
||||
CharData("\n "),
|
||||
CharData("Some text here."),
|
||||
CharData("\n "),
|
||||
EndElement{Name{"ns3", "name"}},
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
EndElement{Name{"ns2", "body"}},
|
||||
Comment([]byte(" missing final newline ")),
|
||||
Comment(" missing final newline "),
|
||||
}
|
||||
|
||||
const testInputAltEncoding = `
|
||||
@ -101,11 +99,11 @@ const testInputAltEncoding = `
|
||||
<TAG>VALUE</TAG>`
|
||||
|
||||
var rawTokensAltEncoding = []Token{
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
StartElement{Name{"", "tag"}, []Attr{}},
|
||||
CharData([]byte("value")),
|
||||
CharData("value"),
|
||||
EndElement{Name{"", "tag"}},
|
||||
}
|
||||
|
||||
@ -270,21 +268,21 @@ var nestedDirectivesInput = `
|
||||
`
|
||||
|
||||
var nestedDirectivesTokens = []Token{
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`)),
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE [<!ENTITY xlt ">">]`)),
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE [<!ENTITY xlt "<">]`)),
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE [<!ENTITY xlt '>'>]`)),
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE [<!ENTITY xlt '<'>]`)),
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE [<!ENTITY xlt '">'>]`)),
|
||||
CharData([]byte("\n")),
|
||||
Directive([]byte(`DOCTYPE [<!ENTITY xlt "'<">]`)),
|
||||
CharData([]byte("\n")),
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`),
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE [<!ENTITY xlt ">">]`),
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE [<!ENTITY xlt "<">]`),
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE [<!ENTITY xlt '>'>]`),
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE [<!ENTITY xlt '<'>]`),
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE [<!ENTITY xlt '">'>]`),
|
||||
CharData("\n"),
|
||||
Directive(`DOCTYPE [<!ENTITY xlt "'<">]`),
|
||||
CharData("\n"),
|
||||
}
|
||||
|
||||
func TestNestedDirectives(t *testing.T) {
|
||||
|
@ -48,23 +48,23 @@ type sniffSig interface {
|
||||
|
||||
// Data matching the table in section 6.
|
||||
var sniffSignatures = []sniffSig{
|
||||
htmlSig([]byte("<!DOCTYPE HTML")),
|
||||
htmlSig([]byte("<HTML")),
|
||||
htmlSig([]byte("<HEAD")),
|
||||
htmlSig([]byte("<SCRIPT")),
|
||||
htmlSig([]byte("<IFRAME")),
|
||||
htmlSig([]byte("<H1")),
|
||||
htmlSig([]byte("<DIV")),
|
||||
htmlSig([]byte("<FONT")),
|
||||
htmlSig([]byte("<TABLE")),
|
||||
htmlSig([]byte("<A")),
|
||||
htmlSig([]byte("<STYLE")),
|
||||
htmlSig([]byte("<TITLE")),
|
||||
htmlSig([]byte("<B")),
|
||||
htmlSig([]byte("<BODY")),
|
||||
htmlSig([]byte("<BR")),
|
||||
htmlSig([]byte("<P")),
|
||||
htmlSig([]byte("<!--")),
|
||||
htmlSig("<!DOCTYPE HTML"),
|
||||
htmlSig("<HTML"),
|
||||
htmlSig("<HEAD"),
|
||||
htmlSig("<SCRIPT"),
|
||||
htmlSig("<IFRAME"),
|
||||
htmlSig("<H1"),
|
||||
htmlSig("<DIV"),
|
||||
htmlSig("<FONT"),
|
||||
htmlSig("<TABLE"),
|
||||
htmlSig("<A"),
|
||||
htmlSig("<STYLE"),
|
||||
htmlSig("<TITLE"),
|
||||
htmlSig("<B"),
|
||||
htmlSig("<BODY"),
|
||||
htmlSig("<BR"),
|
||||
htmlSig("<P"),
|
||||
htmlSig("<!--"),
|
||||
|
||||
&maskedSig{mask: []byte("\xFF\xFF\xFF\xFF\xFF"), pat: []byte("<?xml"), skipWS: true, ct: "text/xml; charset=utf-8"},
|
||||
|
||||
|
@ -185,7 +185,7 @@ func (a *Address) String() string {
|
||||
type addrParser []byte
|
||||
|
||||
func newAddrParser(s string) *addrParser {
|
||||
p := addrParser([]byte(s))
|
||||
p := addrParser(s)
|
||||
return &p
|
||||
}
|
||||
|
||||
|
96
test/convert1.go
Normal file
96
test/convert1.go
Normal file
@ -0,0 +1,96 @@
|
||||
// errchk $G -e $D/$F.go
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type Tbyte []byte
|
||||
type Trune []rune
|
||||
type Tint64 []int64
|
||||
type Tstring string
|
||||
|
||||
func main() {
|
||||
s := "hello"
|
||||
sb := []byte("hello")
|
||||
sr := []rune("hello")
|
||||
si := []int64{'h', 'e', 'l', 'l', 'o'}
|
||||
|
||||
ts := Tstring(s)
|
||||
tsb := Tbyte(sb)
|
||||
tsr := Trune(sr)
|
||||
tsi := Tint64(si)
|
||||
|
||||
_ = string(s)
|
||||
_ = []byte(s)
|
||||
_ = []rune(s)
|
||||
_ = []int64(s) // ERROR "cannot convert.*\[\]int64"
|
||||
_ = Tstring(s)
|
||||
_ = Tbyte(s)
|
||||
_ = Trune(s)
|
||||
_ = Tint64(s) // ERROR "cannot convert.*Tint64"
|
||||
|
||||
_ = string(sb)
|
||||
_ = []byte(sb)
|
||||
_ = []rune(sb) // ERROR "cannot convert.*\[\]rune"
|
||||
_ = []int64(sb) // ERROR "cannot convert.*\[\]int64"
|
||||
_ = Tstring(sb)
|
||||
_ = Tbyte(sb)
|
||||
_ = Trune(sb) // ERROR "cannot convert.*Trune"
|
||||
_ = Tint64(sb) // ERROR "cannot convert.*Tint64"
|
||||
|
||||
_ = string(sr)
|
||||
_ = []byte(sr) // ERROR "cannot convert.*\[\]byte"
|
||||
_ = []rune(sr)
|
||||
_ = []int64(sr) // ERROR "cannot convert.*\[\]int64"
|
||||
_ = Tstring(sr)
|
||||
_ = Tbyte(sr) // ERROR "cannot convert.*Tbyte"
|
||||
_ = Trune(sr)
|
||||
_ = Tint64(sr) // ERROR "cannot convert.*Tint64"
|
||||
|
||||
_ = string(si) // ERROR "cannot convert.* string"
|
||||
_ = []byte(si) // ERROR "cannot convert.*\[\]byte"
|
||||
_ = []rune(si) // ERROR "cannot convert.*\[\]rune"
|
||||
_ = []int64(si)
|
||||
_ = Tstring(si) // ERROR "cannot convert.*Tstring"
|
||||
_ = Tbyte(si) // ERROR "cannot convert.*Tbyte"
|
||||
_ = Trune(si) // ERROR "cannot convert.*Trune"
|
||||
_ = Tint64(si)
|
||||
|
||||
_ = string(ts)
|
||||
_ = []byte(ts)
|
||||
_ = []rune(ts)
|
||||
_ = []int64(ts) // ERROR "cannot convert.*\[\]int64"
|
||||
_ = Tstring(ts)
|
||||
_ = Tbyte(ts)
|
||||
_ = Trune(ts)
|
||||
_ = Tint64(ts) // ERROR "cannot convert.*Tint64"
|
||||
|
||||
_ = string(tsb)
|
||||
_ = []byte(tsb)
|
||||
_ = []rune(tsb) // ERROR "cannot convert.*\[\]rune"
|
||||
_ = []int64(tsb) // ERROR "cannot convert.*\[\]int64"
|
||||
_ = Tstring(tsb)
|
||||
_ = Tbyte(tsb)
|
||||
_ = Trune(tsb) // ERROR "cannot convert.*Trune"
|
||||
_ = Tint64(tsb) // ERROR "cannot convert.*Tint64"
|
||||
|
||||
_ = string(tsr)
|
||||
_ = []byte(tsr) // ERROR "cannot convert.*\[\]byte"
|
||||
_ = []rune(tsr)
|
||||
_ = []int64(tsr) // ERROR "cannot convert.*\[\]int64"
|
||||
_ = Tstring(tsr)
|
||||
_ = Tbyte(tsr) // ERROR "cannot convert.*Tbyte"
|
||||
_ = Trune(tsr)
|
||||
_ = Tint64(tsr) // ERROR "cannot convert.*Tint64"
|
||||
|
||||
_ = string(tsi) // ERROR "cannot convert.* string"
|
||||
_ = []byte(tsi) // ERROR "cannot convert.*\[\]byte"
|
||||
_ = []rune(tsi) // ERROR "cannot convert.*\[\]rune"
|
||||
_ = []int64(tsi)
|
||||
_ = Tstring(tsi) // ERROR "cannot convert.*Tstring"
|
||||
_ = Tbyte(tsi) // ERROR "cannot convert.*Tbyte"
|
||||
_ = Trune(tsi) // ERROR "cannot convert.*Trune"
|
||||
_ = Tint64(tsi)
|
||||
}
|
@ -54,12 +54,12 @@ var _ = []byte(ss)
|
||||
var _ []rune = ss // ERROR "cannot use|incompatible|invalid"
|
||||
var _ []byte = ss // ERROR "cannot use|incompatible|invalid"
|
||||
|
||||
// named slice is not
|
||||
// named slice is now ok
|
||||
type Trune []rune
|
||||
type Tbyte []byte
|
||||
|
||||
var _ = Trune("abc") // ERROR "convert|incompatible|invalid"
|
||||
var _ = Tbyte("abc") // ERROR "convert|incompatible|invalid"
|
||||
var _ = Trune("abc") // ok
|
||||
var _ = Tbyte("abc") // ok
|
||||
|
||||
// implicit is still not
|
||||
var _ Trune = "abc" // ERROR "cannot use|incompatible|invalid"
|
||||
|
@ -57,5 +57,5 @@ func main() {
|
||||
_, b = <-c // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b
|
||||
|
||||
asString(String(slice)) // ERROR "cannot .*type Slice.*type String"
|
||||
asString(String(slice)) // ok
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user