在Go中解释类型断言

在Go中解释类型断言,第1张

在Go中解释类型断言 简短答案

一行:

x.(T)
断言
x
不是nil并且存储的值
x
是type
T

我为什么要使用它们:
  • 检查
    x
    为零
  • 检查它是否可转换(断言)为另一种类型
  • 转换(断言)为另一种类型
他们到底返回什么:
  • t := x.(T)
    => t是类型
    T
    ;如果
    x
    为零,则表示恐慌。

  • t,ok := x.(T)
    =>如果
    x
    是零或不类型
    T
    =>
    ok
    false
    否则
    ok
    true
    t
    是类型的
    T


详细说明

假设您需要计算4种不同形状的面积:圆形,正方形,矩形和三角形。您可以使用称为的新方法来定义新类型

Area()
,如下所示:

type Circle struct {    Radius float64}func (t Circle) Area() float64 {    return math.Pi * t.Radius * t.Radius}

对于

Triangle

type Triangle struct {    A, B, C float64 // lengths of the sides of a triangle.}func (t Triangle) Area() float64 {    p := (t.A + t.B + t.C) / 2.0 // perimeter half    return math.Sqrt(p * (p - t.A) * (p - t.B) * (p - t.C))}

对于

Rectangle

type Rectangle struct {    A, B float64}func (t Rectangle) Area() float64 {    return t.A * t.B}

对于

Square

type Square struct {    A float64}func (t Square) Area() float64 {    return t.A * t.A}

在这里,您有

Circle
,其半径为1.0,其侧面具有其他形状:

shapes := []Shape{    Circle{1.0},    Square{1.772453},    Rectangle{5, 10},    Triangle{10, 4, 7},}

有趣!我们如何将它们全部收集在一个地方?
首先,您需要

Shape interface
将它们全部收集成一片形状
[]Shape

type Shape interface {    Area() float64}

现在,您可以像这样收集它们:

shapes := []Shape{    Circle{1.0},    Square{1.772453},    Rectangle{5, 10},    Triangle{10, 4, 7},}

毕竟,

Circle
Shape
Triangle
Shape
太。
现在,您可以使用单个语句打印每个形状的区域
v.Area()

for _, v := range shapes {    fmt.Println(v, "tArea:", v.Area())}

Area()
所有形状之间的通用接口也是如此。现在,我们如何使用上述方法来计算和调用像三角形的角之类的不常见方法
shapes

func (t Triangle) Angles() []float64 {    return []float64{angle(t.B, t.C, t.A), angle(t.A, t.C, t.B), angle(t.A, t.B, t.C)}}func angle(a, b, c float64) float64 {    return math.Acos((a*a+b*b-c*c)/(2*a*b)) * 180.0 / math.Pi}

现在是时候

Triangle
从上方提取
shapes

for _, v := range shapes {    fmt.Println(v, "tArea:", v.Area())    if t, ok := v.(Triangle); ok {        fmt.Println("Angles:", t.Angles())    }}

使用

t, ok := v.(Triangle)
我们要求的类型断言,这意味着我们要求编译器尝试将
v
type 转换
Shape
为type
Triangle
,以便如果成功,
ok
则将为
true
否则
false
,然后如果成功,则调用
t.Angles()
计算三角形的三个角度。

这是输出:

Circle (Radius: 1)  Area: 3.141592653589793Square (Sides: 1.772453)    Area: 3.1415896372090004Rectangle (Sides: 5, 10)    Area: 50Triangle (Sides: 10, 4, 7)  Area: 10.928746497197197Angles: [128.68218745348943 18.194872338766785 33.12294020774379]

以及整个工作示例代码:

package mainimport "fmt"import "math"func main() {    shapes := []Shape{        Circle{1.0},        Square{1.772453},        Rectangle{5, 10},        Triangle{10, 4, 7},    }    for _, v := range shapes {        fmt.Println(v, "tArea:", v.Area())        if t, ok := v.(Triangle); ok { fmt.Println("Angles:", t.Angles())        }    }}type Shape interface {    Area() float64}type Circle struct {    Radius float64}type Triangle struct {    A, B, C float64 // lengths of the sides of a triangle.}type Rectangle struct {    A, B float64}type Square struct {    A float64}func (t Circle) Area() float64 {    return math.Pi * t.Radius * t.Radius}// Heron's Formula for the area of a trianglefunc (t Triangle) Area() float64 {    p := (t.A + t.B + t.C) / 2.0 // perimeter half    return math.Sqrt(p * (p - t.A) * (p - t.B) * (p - t.C))}func (t Rectangle) Area() float64 {    return t.A * t.B}func (t Square) Area() float64 {    return t.A * t.A}func (t Circle) String() string {    return fmt.Sprint("Circle (Radius: ", t.Radius, ")")}func (t Triangle) String() string {    return fmt.Sprint("Triangle (Sides: ", t.A, ", ", t.B, ", ", t.C, ")")}func (t Rectangle) String() string {    return fmt.Sprint("Rectangle (Sides: ", t.A, ", ", t.B, ")")}func (t Square) String() string {    return fmt.Sprint("Square (Sides: ", t.A, ")")}func (t Triangle) Angles() []float64 {    return []float64{angle(t.B, t.C, t.A), angle(t.A, t.C, t.B), angle(t.A, t.B, t.C)}}func angle(a, b, c float64) float64 {    return math.Acos((a*a+b*b-c*c)/(2*a*b)) * 180.0 / math.Pi}

另请参阅:

类型断言

对于具有接口类型和类型T的表达式x,主要表达式

x.(T)

断言x不为nil,并且x中存储的值的类型为T。符号x。(T)称为类型断言。

更准确地说,如果T不是接口类型,则x。(T)断言x的动态类型与T的类型相同。在这种情况下,T必须实现x的(接口)类型。否则,类型断言无效,因为x不可能存储类型T的值。如果T是接口类型,则x。(T)断言x的动态类型实现了接口T。

如果类型断言成立,则表达式的值为存储在x中的值,其类型为T。 如果类型断言为false,则会发生运行时恐慌。
换句话说,即使x的动态类型仅在运行时才知道,但在正确的程序中x。(T)的类型还是T。

var x interface{} = 7  // x has dynamic type int and value 7i := x.(int)// i has type int and value 7type I interface { m() }var y Is := y.(string)        // illegal: string does not implement I (missing

method m)
r := y.(io.Reader) // r has type io.Reader and y must implement both
I and io.Reader

在特殊形式的赋值或初始化中使用的类型断言

v, ok = x.(T)v, ok := x.(T)var v, ok = x.(T)

产生另一个无类型的布尔值。如果断言成立,则ok的值为true。否则为false,并且v的值为T类型的零值。 在这种情况下,不会发生运行时恐慌


编辑

问题

x.(T)
当T是an
interface{}
而不是具体类型时,断言返回什么?

它断言x不是nil,并且x中存储的值是T类型。

例如,此恐慌(编译:成功,运行:)

panic: interface conversion: interface is nil, not interface{}

package mainfunc main() {    var i interface{} // nil    var _ = i.(interface{})}

这可行(运行:确定):

package mainimport "fmt"func main() {    var i interface{} // nil    b, ok := i.(interface{})    fmt.Println(b, ok) // <nil> false    i = 2    c, ok := i.(interface{})    fmt.Println(c, ok) // 2 true    //var j int = c // cannot use c (type interface {}) as type int in assignment: need type assertion    //fmt.Println(j)}

输出:

<nil> false2 true

注意: 这里

c
是类型
interface {}
而不是
int

请参阅以下带有注释输出的工作示例代码:

package mainimport "fmt"func main() {    const fm = "'%T't'%#[1]v't'%[1]v't%vn"    var i interface{}    b, ok := i.(interface{})    fmt.Printf(fm, b, ok) // '<nil>'    '<nil>' '<nil>' false    i = 2    b, ok = i.(interface{})    fmt.Printf(fm, b, ok) // 'int'  '2' '2' true    i = "Hi"    b, ok = i.(interface{})    fmt.Printf(fm, b, ok) // 'string'   '"Hi"'  'Hi'    true    i = new(interface{})    b, ok = i.(interface{})    fmt.Printf(fm, b, ok) // '*interface {}'    '(*interface {})(0xc042004330)' '0xc042004330'  true    i = struct{}{}    b, ok = i.(interface{})    fmt.Printf(fm, b, ok) // 'struct {}'    'struct {}{}'   '{}'    true    i = fmt.Println    b, ok = i.(interface{})    fmt.Printf(fm, b, ok) // 'func(...interface {}) (int, error)'   '(func(...interface {}) (int, error))(0x456740)'    '0x456740'  true    i = Shape.Area    b, ok = i.(interface{})    fmt.Printf(fm, b, ok) // 'func(main.Shape) float64' '(func(main.Shape) float64)(0x401910)'  '0x401910'  true}type Shape interface {    Area() float64}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5086593.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-11-16
下一篇2022-11-16

发表评论

登录后才能评论

评论列表(0条)

    保存