Bagikan melalui


tentang_Konversi_Tipe

Deskripsi singkat

PowerShell memiliki sistem jenis fleksibel yang membuatnya lebih mudah digunakan. Namun, Anda harus memahami cara kerjanya untuk menghindari hasil yang tidak terduga.

Deskripsi panjang

Secara bawaan, variabel PowerShell tidak terikat tipe. Anda dapat membuat variabel yang berisi instans dari satu jenis dan kemudian menetapkan nilai dari jenis lain. Selain itu, PowerShell secara otomatis mengonversi nilai ke jenis lain, baik secara eksplisit maupun implisit. Meskipun konversi jenis implisit dapat membantu, ada jebakan, terutama untuk pengguna yang lebih akrab dengan bahasa yang memiliki penanganan jenis yang lebih ketat.

Variabel yang dibatasi jenis dan konversi jenis eksplisit

Untuk membatasi jenis variabel, tempatkan jenis harfiah di sebelah kiri nama variabel dalam penugasan. Misalnya:

[int]$foo = 42

Anda dapat menggunakan pengubahan tipe untuk mengonversi nilai secara eksplisit ke jenis tertentu. Misalnya:

PS> $var = [int]'43'
PS> $var.GetType().Name
Int32

Pembatasan jenis memastikan bahwa hanya nilai dari jenis yang ditentukan yang dapat ditetapkan ke variabel. PowerShell melakukan konversi implisit jika Anda mencoba menetapkan nilai dari jenis berbeda yang dapat dikonversi ke jenis yang dibatasi. Untuk informasi lebih lanjut, lihat bagian konversi jenis implisit di artikel ini.

Konversi jenis numerik

Jenis numerik dapat dikonversi ke jenis numerik lainnya selama jenis target mampu menahan nilai yang dikonversi. Misalnya:

PS> (42.1).GetType().Name
Double
PS> $byte = [byte] 42.1
PS> $byte
42
PS> $byte.GetType().Name
Byte

Nilai 42.1 adalah Ganda. Ketika Anda mengubahnya menjadi Byte , PowerShell memotongnya menjadi bilangan bulat 42, yang cukup kecil untuk dimasukkan ke dalam Byte .

Saat mengonversi angka riil ke jenis bilangan bulat, PowerShell menggunakan pembulatan daripada pemotongan, khususnya menggunakan metode pembulatan-ke-terdekat-genap . Contoh berikut mengilustrasikan perilaku ini. Kedua nilai dibulatkan ke bilangan bulat genap terdekat, 22.

PS> [byte]21.5
22
PS> [byte]22.5
22

Untuk informasi selengkapnya, lihat bagian Nilai Titik Tengah dan Konvensi Pembulatan dari metode Math.Round.

Konversi jenis Boolean

Nilai jenis apa pun dapat dipaksa menjadi Boolean.

  • Untuk jenis numerik, 0 dikonversi ke $false dan nilai lainnya dikonversi ke $true.

    PS> [boolean]0
    False
    PS> [boolean]0.0
    False
    PS> [boolean]-1
    True
    PS> [boolean]1
    True
    PS> [boolean]42.1
    True
    
  • Untuk jenis lain, nilai null, string kosong, dan array kosong dikonversi ke $false.

    PS> [boolean]''
    False
    PS> [boolean]@()
    False
    PS> [boolean]'Hello'
    True
    

    Nilai lain, termasuk hashtable yang kosong, dikonversi menjadi $true. Koleksi elemen tunggal mengevaluasi ke nilai Boolean dari satu dan satu-satunya elemennya. Koleksi yang memiliki lebih dari 1 elemen selalu $true.

    PS> [boolean]@(0)
    False
    PS> [boolean]@(0,0)
    True
    PS> [boolean]@{}
    True
    

Konversi jenis string

Nilai jenis apa pun dapat diubah menjadi String . Konversi default adalah memanggil metode ToString() pada objek.

Array dikonversi menjadi string. Setiap elemen dalam array dikonversi menjadi string, satu per satu dan digabungkan ke string yang dihasilkan. Secara default, nilai yang dikonversi dipisahkan oleh spasi. Pemisah dapat diubah dengan mengatur variabel preferensi $OFS.

PS> [string] @(1, 2, 3)
1 2 3

Untuk informasi selengkapnya tentang $OFS, lihat about_Preference_Variables.

Nilai string tunggal dapat dikonversi ke instans jenis jika jenis mengimplementasikan metode Parse() statis. Misalnya, [bigint]'42' sama dengan [bigint]::Parse('42', [cultureinfo]::InvariantCulture). Nilai [cultureinfo]::InvariantCulture opsional mengikat parameter jenis IFormatProvider metode. Ini memastikan perilaku konversi yang tidak berubah oleh budaya. Tidak semua implementasi metode Parse() memiliki parameter ini.

Nota

Konversi ke dan dari string biasanya dilakukan menggunakan budaya invarian . Budaya invarian didasarkan pada, tetapi tidak identik dengan, budaya US-English. Terutama, ia menggunakan periode (.) sebagai tanda desimal dan tanggal pertama bulan gaya AS secara default. Namun, cmdlet biner melakukan konversi yang peka terhadap budaya selama pengikatan parameter.

Konversi jenis enum

PowerShell dapat mengonversi Enum ke atau dari instans String. Misalnya, string typecast [System.PlatformId]'Unix' sama dengan nilai enum [System.PlatformId]::Unix. PowerShell juga menangani enum berbasis flag dengan benar untuk nilai yang dipisahkan oleh tanda koma di dalam string atau sebagai array dari string. Pertimbangkan contoh berikut:

[System.Reflection.TypeAttributes]'Public, Abstract'
[System.Reflection.TypeAttributes]('Public', 'Abstract')

Contoh-contoh ini setara dengan ekspresi enum:

[System.Reflection.TypeAttributes]::Public -bor
    [System.Reflection.TypeAttributes]::Abstract

Konversi jenis lainnya

Nilai tunggal (non-array) dapat dikonversi ke instans jenis jika:

  • Jenis tersebut memiliki konstruktor parameter tunggal (publik)
  • Dan nilainya memiliki jenis yang sama atau dapat diubah menjadi jenis dari parameter

Misalnya, dua baris berikut setara:

[regex]'a|b'
[regex]::new('a|b')`

Jenis implisit

PowerShell juga menetapkan jenis ke nilai harfiah secara otomatis.

Literal numerik secara implisit ditik secara default. Angka diketik berdasarkan ukuran mereka. Misalnya, cukup kecil untuk disimpan sebagai jenis Int32 dan disimpan sebagai Double. Bilangan bulat yang lebih besar dari [int32]::MaxValue disimpan sebagai Int64. Meskipun dapat disimpan sebagai Byte dan dapat disimpan sebagai tipe Single , pengetikan implisit menggunakan Int32 dan Double masing-masing. Untuk informasi selengkapnya, lihat about_Numeric_Literals.

String literal secara implisit dititikkan sebagai string . Instans String karakter tunggal dapat dikonversi ke dan dari tipe Char. Namun, PowerShell tidak memiliki jenis literal Char .

Konversi jenis implisit

Dalam konteks tertentu, PowerShell dapat secara implisit mengonversi nilai ke jenis lain. Konteks ini meliputi:

  • Pengikatan parameter
  • Variabel yang dibatasi jenis
  • Ekspresi menggunakan operator
  • Konteks Boolean - PowerShell mengonversi ekspresi kondisional pernyataan if, while, do, atau switch menjadi nilai Boolean, seperti yang dijelaskan sebelumnya. Untuk informasi selengkapnya, lihat about_Booleans.
  • Definisi jenis Extended Type System (ETS) - Konversi jenis dapat ditentukan dalam beberapa cara:

Konversi pengikatan parameter

PowerShell mencoba mengonversi nilai yang diteruskan ke parameter agar sesuai dengan jenis parameter. Konversi jenis nilai parameter terjadi dalam cmdlet, fungsi, skrip, blok skrip, atau metode .NET tempat parameter dideklarasikan dengan jenis tertentu. Mendeklarasikan parameter dengan jenis [Object] atau tidak menentukan jenis tertentu memungkinkan jenis nilai apa pun diteruskan ke parameter. Parameter juga dapat memiliki konversi kustom yang ditentukan dengan mendekorasi parameter menggunakan atribut ArgumentTransformationAttribute.

Untuk informasi selengkapnya, lihat about_Parameter_Binding.

Praktik terbaik untuk pengikatan parameter

Untuk metode .NET, lebih baik memberikan tipe yang tepat yang diharapkan dengan menggunakan pengubahan tipe jika diperlukan. Tanpa jenis yang tepat, PowerShell dapat memilih metode yang salah kelebihan beban. Selain itu, kelebihan beban metode baru yang ditambahkan dalam versi .NET yang akan datang dapat merusak kode yang ada. Untuk contoh ekstrem dari masalah ini, lihat pertanyaan Stack Overflow ini.

Jika Anda meneruskan array ke parameter [string] yang ditik, PowerShell mungkin mengonversi array menjadi string seperti yang dijelaskan sebelumnya. Pertimbangkan fungsi dasar berikut:

function Test-String {
    param([string] $String)
    $String
}

Test-String -String 1, 2

Fungsi ini menghasilkan 1 2 karena array dikonversi menjadi string. Untuk menghindari perilaku ini, buat fungsi tingkat lanjut dengan menambahkan atribut .

function Test-String {
    [CmdletBinding()]
    param([string] $String)
    $String
}

Test-String -String 1, 2

Untuk fungsi tingkat lanjut, PowerShell menolak untuk mengikat array ke jenis non-array. Saat Anda meneruskan array, PowerShell mengembalikan pesan kesalahan berikut:

Test-String:
Line |
   7 |  Test-String -String 1, 2
     |                      ~~~~
     | Cannot process argument transformation on parameter 'String'. Cannot
     | convert value to type System.String.

Sayangnya, Anda tidak dapat menghindari perilaku ini untuk panggilan metode .NET.

PS> (Get-Date).ToString(@(1, 2))
1 2

PowerShell mengonversi array ke string , yang diteruskan ke parameter Format dari metode .

Contoh berikut menunjukkan instans lain dari masalah konversi larik.

PS> $bytes = [byte[]] @(1..16)
PS> $guid = New-Object System.Guid($bytes)
New-Object: Cannot find an overload for "Guid" and the argument count: "16".

PowerShell memperlakukan array $bytes sebagai daftar parameter individual meskipun $bytes adalah array byte dan System.Guid memiliki konstruktor Guid(byte[]).

Pola kode umum ini adalah contoh sintaks metode semu , yang tidak selalu berfungsi seperti yang dimaksudkan. Sintaks ini diterjemahkan ke:

PS> [byte[]] $bytes = 1..16
PS> New-Object -TypeName System.Guid -ArgumentList $bytes
New-Object: Cannot find an overload for "Guid" and the argument count: "16".

Mengingat bahwa jenis ArgumentList adalah [Object[]], sebuah argumen tunggal yang kebetulan merupakan array (dari jenis apa pun) mengikat per elemen . Solusinya adalah membungkus $bytes dalam array luar sehingga PowerShell mencari konstruktor dengan parameter yang cocok dengan konten array luar.

PS> [byte[]] $bytes = 1..16
PS> $guid = New-Object -TypeName System.Guid -ArgumentList (, $bytes)
PS> $guid

Guid
----
04030201-0605-0807-090a-0b0c0d0e0f10

Item pertama dari array yang dibungkus adalah instans [byte[]] asli kami. Nilai tersebut cocok dengan konstruktor Guid(byte[]).

Alternatif untuk solusi pembungkusan array adalah dengan menggunakan metode new() statis intrinsik.

PS> [byte[]] $bytes = 1..16
PS> [System.Guid]::new($bytes)  # OK

Guid
----
04030201-0605-0807-090a-0b0c0d0e0f10

Konversi variabel dengan pembatasan tipe

Saat Anda menetapkan nilai ke variabel yang dibatasi jenis, PowerShell mencoba mengonversi nilai ke jenis variabel. Jika nilai yang disediakan dapat dikonversi ke jenis variabel, penugasan berhasil.

Misalnya:

PS> [int]$foo = '43'
PS> $foo.GetType().Name
Int32

Konversi berfungsi karena string '43' dapat dikonversi menjadi angka.

Konversi operator

PowerShell dapat secara implisit mengonversi operand dalam ekspresi untuk menghasilkan hasil yang wajar. Selain itu, beberapa operator memiliki perilaku khusus jenis.

Operasi numerik

Dalam operasi numerik, bahkan jika kedua operand adalah jenis numerik yang sama, hasilnya bisa menjadi jenis yang berbeda, karena konversi jenis otomatis untuk mengakomodasi hasilnya.

PS> [int]$a = 1
PS> [int]$b = 2
PS> $result = $a / $b
PS> $result
0.5
PS> $result.GetType().Name
Double

Meskipun kedua operand adalah bilangan bulat, hasilnya dikonversi ke Double untuk mendukung hasil pecahan. Untuk mendapatkan pembagian bilangan bulat sejati, gunakan metode statis [int]::Truncate() atau [Math]::DivRem(). Untuk informasi selengkapnya, lihat Truncate() dan DivRem().

Dalam aritmatika bilangan bulat, ketika hasil melebihi ukuran operand, PowerShell secara default menggunakan Double untuk hasilnya, bahkan ketika hasilnya dapat masuk ke dalam tipe Int64.

PS> $result = [int]::MaxValue + 1
PS> $result
2147483648
PS> $result.GetType().Name
Double

Jika Anda ingin hasilnya menjadi Int64, Anda dapat mengonversi tipe hasil atau operan.

PS> ([int64]([int]::MaxValue + 1)).GetType().Name
Int64

Namun, gunakan kehati-hatian saat mengonversi hasil ke tipe data tertentu. Misalnya, penyaringan tipe hasil ke tipe [decimal] dapat menyebabkan hilangnya presisi. Menambahkan ke nilai maksimum Int64 menghasilkan jenis Ganda . Saat Anda mengonversi Double ke tipe Desimal , hasilnya 9223372036854780000, yang tidak akurat.

PS> ([int64]::MaxValue + 1).GetType().Name
Double
PS> [decimal]([int64]::MaxValue + 1)
9223372036854780000

Konversi dibatasi hingga 15 digit presisi. Untuk informasi selengkapnya, lihat bagian Keterangan dari dokumentasi konstruktor Decimal(Ganda).

Untuk menghindari hilangnya presisi, gunakan akhiran D pada literal 1. Dengan menambahkan akhiran , PowerShell mengonversi ke Desimal sebelum menambahkan .

PS> ([int64]::MaxValue + 1D).GetType().Name
Decimal
PS> ([int64]::MaxValue + 1D)
9223372036854775808

Untuk informasi selengkapnya tentang akhiran numerik, lihat about_Numeric_Literals.

Biasanya, operan sisi kiri (LHS) operator PowerShell menentukan jenis data yang digunakan dalam operasi. PowerShell mengonversi (memaksa) operand pada sisi kanan (RHS) ke tipe yang diperlukan.

PS> 10 - ' 9 '
1

Dalam contoh ini, operand RHS adalah string ' 9 ', yang secara implisit dikonversi menjadi bilangan bulat sebelum operasi pengurangan. Hal yang sama berlaku untuk operator perbandingan.

PS> 10 -eq ' 10'
True
PS> 10 -eq '0xa'
True

Ada pengecualian saat menggunakan operator aritmatika (+, -, *, /) dengan operan tidak numerik.

Saat Anda menggunakan - dan / operand dengan string, PowerShell mengonversi kedua operan dari string menjadi angka.

PS> '10' - '2'
8
PS> '10' / '2'
5

Sebaliknya, operator + dan * memiliki semantik khusus string (perangkaian dan replikasi).

PS> '10' + '2'
102
PS> '10' * '2'
1010

Saat Anda menggunakan nilai Boolean dengan operator aritmatika, PowerShell mengonversi nilai menjadi bilangan bulat: menjadi dan menjadi .

PS> $false - $true
-1

Satu pengecualian adalah perkalian (*) dari dua boolean.

PS> $false * $true
InvalidOperation: The operation '[System.Boolean] * [System.Boolean]' is not
defined.

Untuk jenis LHS lainnya, operator aritmatika hanya berhasil jika jenis tertentu mendefinisikan operator ini melalui operator kelebihan beban.

Operasi perbandingan

Operator perbandingan, seperti -eq, -lt, dan -gt, dapat membandingkan operan dari berbagai jenis. Perilaku non-string dan jenis non-primitif tergantung pada apakah jenis LHS mengimplementasikan antarmuka seperti IEquatable dan IComparable.

Operator perbandingan berbasis koleksi (-in dan -contains) melakukan per elemen -eq perbandingan hingga kecocokan ditemukan. Ini adalah setiap elemen individu dari operand koleksi yang mendorong paksaan jenis apa pun.

PS> $true -in 'true', 'false'
True
PS> 'true', 'false' -contains $true
True

Kedua contoh mengembalikan true karena 'true' -eq $true menghasilkan $true.

Untuk informasi selengkapnya, lihat about_Comparison_Operators.